How do I append one matrix to another in Scala? - arrays

If I have the following code:
var A = Array[Array[Double]]() // where A becomes an MxP matrix
var B = Array[Array[Double]]() // where B becomes an NxP matrix
What are some efficient ways to append one matrix to the other, resulting in a single matrix, as the following pseudocode would suggest?
val C = A append B // where C is a (M+N)xP matrix
Obviously, one of the dimensions (in this case P) is held constant.
EDIT: So far, both of the provided solutions are growing in the second dimension. I am trying to hold the second dimension fixed.

Functional, but not as performant as the imperative alternative would be:
scala> val a = Array.tabulate(2, 3)((_, _) => (math.random * 100).toInt)
a: Array[Array[Int]] = Array(Array(52, 61, 58), Array(35, 69, 39))
scala> val b = Array.tabulate(2, 4)((_, _) => (math.random * 100).toInt)
b: Array[Array[Int]] = Array(Array(51, 54, 87, 10), Array(52, 76, 18, 85))
scala> (a, b).zipped.map(_ ++ _)
res0: Array[Array[Int]] = Array(Array(52, 61, 58, 51, 54, 87, 10), Array(35, 69, 39, 52, 76, 18, 85))
(In reply to the comment...)
Holding the second dimension fixed:
scala> val x = Array.tabulate(3, 2)((_, _) => (math.random * 100).toInt)
x: Array[Array[Int]] = Array(Array(13, 26), Array(96, 6), Array(68, 58))
scala> val y = Array.tabulate(2, 2)((_, _) => (math.random * 100).toInt)
y: Array[Array[Int]] = Array(Array(82, 5), Array(0, 76))
scala> x ++ y
res1: Array[Array[Int]] = Array(Array(13, 26), Array(96, 6), Array(68, 58), Array(82, 5), Array(0, 76))

scala> val a = Array.fill(4,3) { 1. };
a: Array[Array[Double]] = Array(Array(1.0, 1.0, 1.0), Array(1.0, 1.0, 1.0), Array(1.0, 1.0, 1.0), Array(1.0, 1.0, 1.0))
scala> val b = Array.fill(4,6) { 2. };
b: Array[Array[Double]] = Array(Array(2.0, 2.0, 2.0, 2.0, 2.0, 2.0), Array(2.0, 2.0, 2.0, 2.0, 2.0, 2.0), Array(2.0, 2.0, 2.0, 2.0, 2.0, 2.0), Array(2.0, 2.0, 2.0, 2.0, 2.0, 2.0))
scala> for((aa,bb) <- a zip b) yield (aa ++ bb)
res0: Array[Array[Double]] = Array(Array(1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0), Array(1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0), Array(1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0), Array(1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0))

Related

Convert image in list of coordinates in Julia

I have this short code img_lab = rand(Lab, 10, 10) where I just have created an image of random colored pixels. Probably this question is trivial but how do I convert the output of this (which is Matrix{Lab{Float64}} (alias for Array{Lab{Float64}, 2}) to an organized list of coordinates.
For example [[0,0,0.44,0.33,0.45],[0,1, ...] , ... , [10,10,0.54,0.32,0.87]]
where the first two entries are the coordinates and the last three values for RGB.
First, please make sure that you have good reasons to do this. Converting to such a format makes it harder to use the rest of Colors functionality, could have a (potentially large) performance cost, and is usually unnecessary.
Now, assuming it's necessary, here's one way to do it:
julia> using Random; Random.seed!(42)
TaskLocalRNG()
julia> img_lab = rand(Lab, 10, 10)
10×10 Matrix{Lab{Float64}}:
Lab(17.3575, -26.8628, -55.5385) Lab(9.1585, 86.3359, 71.5105) … Lab(14.4465, 87.7468, 12.1242)
Lab(16.6439, 11.0078, -10.1264) Lab(54.2929, -24.2044, -55.6044) Lab(5.5968, 79.2197, -6.69094)
Lab(39.0663, 61.8604, 90.5844) Lab(50.2836, -78.3482, -26.4757) Lab(6.6672, 21.7418, -100.172)
.
.
.
julia> map(keys(img_lab)) do cindex
rgbval = RGB(img_lab[cindex])
[cindex[1], cindex[2], red(rgbval), green(rgbval), blue(rgbval)]
end
10×10 Matrix{Vector{Float64}}:
[1.0, 1.0, 0.0, 0.223779, 0.488699] [1.0, 2.0, 0.468242, 0.0, 0.0] … [1.0, 10.0, 0.513226, 0.0, 0.101153]
[2.0, 1.0, 0.196137, 0.141577, 0.218233] [2.0, 2.0, 0.0, 0.573977, 0.885473] [2.0, 10.0, 0.366805, 0.0, 0.118275]
[3.0, 1.0, 0.737804, 0.0333098, 0.0] [3.0, 2.0, 0.0, 0.583897, 0.639801] [3.0, 10.0, 0.0, 0.136071, 0.65593]
[4.0, 1.0, 0.117582, 0.0803492, 0.209829] [4.0, 2.0, 0.833069, 0.433512, 1.0] [4.0, 10.0, 0.818553, 0.673722, 0.202751]
[5.0, 1.0, 0.0, 0.267613, 0.416236] [5.0, 2.0, 0.0, 1.0, 1.0] [5.0, 10.0, 0.26368, 0.0, 0.0]
[6.0, 1.0, 0.0, 0.703393, 0.0] [6.0, 2.0, 0.89057, 0.980158, 1.0] … [6.0, 10.0, 0.491448, 0.47962, 0.891735]
[7.0, 1.0, 0.0, 1.0, 0.819822] [7.0, 2.0, 1.0, 0.773939, 1.0] [7.0, 10.0, 0.0, 1.0, 1.0]
[8.0, 1.0, 1.0, 0.707005, 0.402694] [8.0, 2.0, 0.0, 0.820631, 1.0] [8.0, 10.0, 0.0, 0.3219, 0.91962]
[9.0, 1.0, 1.0, 0.830982, 0.928663] [9.0, 2.0, 0.0, 0.279664, 0.0] [9.0, 10.0, 0.937227, 0.650945, 0.442197]
[10.0, 1.0, 0.291409, 0.0, 0.28529] [10.0, 2.0, 1.0, 0.682411, 1.0] [10.0, 10.0, 0.0, 0.475448, 0.941526]
(From my limited understanding, Lab-to-RGB conversion is a lossy one - and the number of 0.0s and 1.0s in the color values above seems to indicate that too, values outside the RGB gamut getting clamped to be within its limits.)

How to extract just floats from list

I want to get arrays with floats from A,B,C list.
page = requests.get("http://www.arso.gov.si/potresi/obvestila%20o%20potresih/aip/")
soup = BeautifulSoup(page.content, 'html.parser')
all_tables=soup.find_all('table')
right_table=soup.find('table',class_='online')
A=[]
B=[]
C=[]
for row in right_table.findAll("tr"):
cells = row.findAll('td')
if len(cells)==6:
A.append(cells[1].find(text=True))
B.append(cells[2].find(text=True))
C.append(cells[3].find(text=True))
For now I have variables like this:
A=[u'45.50',u'46.00',...]
and I want just floats from list:
A=[45.50,46.00,...]
Just convert the element's text to float type:
...
if len(cells) == 6:
A.append(float(cells[1].text))
B.append(float(cells[2].text))
C.append(float(cells[3].text))
print(A)
print(B)
print(C)
The output:
[45.5, 46.0, 46.07, 45.89, 45.83, 46.1, 46.53, 45.88, 45.84, 45.9, 46.09, 46.39, 45.3, 45.34, 46.7, 45.25, 46.39, 45.5, 46.39]
[14.41, 14.76, 14.22, 14.59, 15.12, 14.42, 14.57, 15.19, 15.18, 14.57, 14.19, 13.39, 14.62, 14.59, 15.23, 14.58, 15.03, 14.4, 15.03]
[1.2, 1.2, 1.0, 0.8, 1.2, 1.0, 1.1, 1.3, 0.8, 0.9, 0.5, 1.0, 1.3, 2.3, 1.4, 1.9, 0.7, 0.8, 0.4]
You could use python2.7 map function to convert each list of strings to a list of floats:
A = map(float, A)
B = map(float, B)
C = map(float, C)
print A # [45.5, 46.0, 46.07, 45.89, 45.83, 46.1, 46.53, 45.88, 45.84, 45.9, 46.09, 46.39, 45.3, 45.34, 46.7, 45.25, 46.39, 45.5, 46.39]
print B # [14.41, 14.76, 14.22, 14.59, 15.12, 14.42, 14.57, 15.19, 15.18, 14.57, 14.19, 13.39, 14.62, 14.59, 15.23, 14.58, 15.03, 14.4, 15.03]
print C # [1.2, 1.2, 1.0, 0.8, 1.2, 1.0, 1.1, 1.3, 0.8, 0.9, 0.5, 1.0, 1.3, 2.3, 1.4, 1.9, 0.7, 0.8, 0.4]

Ruby: Comparing arrays and creating new ones based on specific conditions

I have 3 arrays of equal length. Some spots are nil, which complicates things, but I need to retain their order.
a = [5.2, 3.0, 1.21, 7.0, 5.0, 5.0, 6.0, 8.0, 10.0, 10.0]
b = [nil, nil, [{"price"=>1.99, "size"=>269.897475661239}], nil, nil, nil, nil, nil, nil, nil]
x = [6.0, 6.2, 2.5, 5.0, 9.0, 2.36, 15.5, 20.0, nil, nil]
(Step One, I want to iterate over b so that b = [nil, nil, 1.99, nil, nil, nil, nil, nil, nil, nil]. Just need ["price"], ignore ["size"]. Couldn't figure that out.)
Step Two, I want to create a new array (c) that averages a and b but where there is nil, just take the one that has a value. In other words, c would = [5.2, 3.0, 1.6, 7.0, 5.0, 5.0, 6.0, 8.0, 10.0, 10.0] which looks like a except the third spot the average of 1.21 and 1.99 (1.6).
So I have my original third array x = [6.0, 6.2, 2.5, 5.0, 9.0, 2.36, 15.5, 20.0, nil, nil]. Step Three, I want to compare c and x to and create a new array z that takes the SMALLER* of the two numbers, or if nil, the one that has a value. z is the result I would like.
Thus z should = [6.0, 6.2, 2.5, 7.0, 9.0, 5.0, 15.5, 20.0, 10.0, 10.0] (if my eyes are correct). (*Edit: I meant the larger of the two numbers, which is why this array doesn't match below answer, so I used that answer below but used .max instead of .min )
I know those steps are tedious, but I need to go in that order because I have lots of arrays where I need to average 2 then compare with a third and take the larger number and with random nil values laced throughout, it gets beyond my abilities. Can't figure it out, and would greatly appreciate some help! Thank you!
bb = b.map { |e| e.is_a?(Array) ? e.first["price"] : e }
#=> [nil, nil, 1.99, nil, nil, nil, nil, nil, nil, nil]
c = a.zip(bb).map { |ea, ebb| ebb.nil? ? ea : (ea+ebb)/2.0 }
#=> [5.2, 3.0, 1.6, 7.0, 5.0, 5.0, 6.0, 8.0, 10.0, 10.0]
c.zip(x).map { |cc,xx| xx.nil? ? cc : [cc,xx].min }
#=> [5.2, 3.0, 1.6, 5.0, 5.0, 2.36, 6.0, 8.0, 10.0, 10.0]
If only bb and the return value were needed, you might perform the following calculation.
[a,bb,x].transpose.map do |ae,bbe,xe|
ab_avg = bbe ? (ae+bbe)/2.0 : ae
xe ? [ab_avg, xe].min : ab_avg
end
#=> [5.2, 3.0, 1.6, 5.0, 5.0, 2.36, 6.0, 8.0, 10.0, 10.0]
Step 1.
b.map!{ |x| x.first.values.first if x }
Step 2.
c = a.map.each_with_index{ |x, i| (x && b[i]) ? ((x || 0) + (b[i] || 0))/2 : (x || b[i]) }
Step 3.
c.map.each_with_index{ |k, i| (k && x[i]) ? [k, x[i]].max : (k || x[i]) }

Count number of Double.NaN values in scala Array

For example:
scala> val my_array = Array(4,5,Double.NaN,6,5,6, Double.NaN)
my_array: Array[Double] = Array(4.0, 5.0, NaN, 6.0, 5.0, 6.0, NaN)
scala> my_array.count(_ == Double.NaN)
res13: Int = 0
I understand that two Double.NaN are not equal to each other
scala> Double.NaN == Double.NaN
res14: Boolean = false
and therefore, I get the result that I get, but I can't find a function that would tell me the number of Double.NaNs, what am I missing?
In python the behaviour would look like this:
In [43]: import numpy as np
In [44]: a = np.array([5,np.nan,5,7,4,np.nan])
In [45]: np.isnan(a)
Out[45]: array([False, True, False, False, False, True], dtype=bool)
In [46]: np.isnan(a).sum()
Out[46]: 2
Double.isNan does the job:
scala> val array = Array(4,5,Double.NaN,6,5,6, Double.NaN)
array: Array[Double] = Array(4.0, 5.0, NaN, 6.0, 5.0, 6.0, NaN)
scala> array.count(_.isNaN)
res0: Int = 2

How to find correspondent elements of two linearly transformed arrays in Ruby?

I have two arrays of floats (x,y) with unique elements, one of them is a linear transform of the other y=a*x+b, for example:
a=0.95;
b1=3.33;
b2=5.55;
x=[1,3,4,6,9,13,20,22,31,35,37,40];
y=t1.collect.with_index{|z,i| i>6 ? z*a+b1 : z*a+b2}
=> [6.5, 8.4, 9.35, 11.25, 14.1, 17.9, 24.55, 24.23, 32.78, 36.58, 38.48, 41.33]
The linear transformation is applied with two different b values to the x array. Let's suppose I don't know the rule of the b values aplied, here the function of the index i.
My goal is that if I know the value of a and I also know the possible values of b in the form of a two element array bs=[b1,b2], then I would like to find out the correspondent b value for every element of y even if the two arrays (x,y) are scrambled. My idea (doesn't work correctly, I need help here):
def ybs(x,y,bs,a)
difference=0.0
xelem=0.0
return y.map do |z|
cb=bs.min_by do |b|
xelem=x.min_by do |q|
(q-(z-b)*1/a).abs
end
difference=(xelem-(z-b)*1/a).abs
end
difference=(xelem-(z-cb)*1/a).abs
[z,xelem,(z-cb)*1/a,cb,difference]
end
end
It would return 4 values for every elements of the y array in the form:
[<value from y>,<correspondent value from x>,<inverse transformed value of y, should be equal to xelem>,<correspondent b value of the linear transformation>,<difference, error, usually 0.0>]
My output when I call ybs(x,y,bs,a):
[[1, 6.5, -2.4526315789473685, 3.33, 8.952631578947368],
[3, 6.5, -0.34736842105263166, 3.33, 6.847368421052631],
[4, 6.5, 0.7052631578947368, 3.33, 5.794736842105263],
[6, 6.5, 2.8105263157894735, 3.33, 3.6894736842105265],
[9, 6.5, 5.968421052631579, 3.33, 0.5315789473684207],
[13, 8.4, 7.842105263157896, 5.55, 0.5578947368421048],
[20, 14.1, 17.547368421052635, 3.33, 3.4473684210526354],
[22, 17.9, 17.31578947368421, 5.55, 0.5842105263157897],
[31, 24.55, 26.789473684210527, 5.55, 2.2394736842105267],
[35, 32.78, 33.33684210526316, 3.33, 0.5568421052631578],
[37, 32.78, 33.10526315789474, 5.55, 0.3252631578947387],
[40, 36.58, 38.6, 3.33, 2.020000000000003]]
I need this method for my subtitle syncing program, where different parts of the subtitles' time codes can be shifted by different amount, for example when a scene is missing from a different version of the movie.
The problem was that you weren't keeping your ordered pairs together. For each y value, your code 'thinks' that the x associated with it is the one for which (q-(z-b)*1/a).abs is the least. However, it could be that taking the "wrong" b value for the y value being considered, together with the wrong x value would lead to a value of (q-(z-b)*1/a).abs that was slightly (or much) less than that which you get by taking the "right" b and x values.
I ran your code (rounding off the values for clarity) and got:
[6.5, 1.0, 1.0, 5.55, 0.0]
[8.4, 3.0, 3.0, 5.55, 0.0]
[9.35, 4.0, 4.0, 5.55, 0.0]
[11.25, 6.0, 6.0, 5.55, 0.0]
[14.1, 9.0, 9.0, 5.55, 0.0]
[17.9, 13.0, 13.0, 5.55, 0.0]
[24.55, 20.0, 20.0, 5.55, 0.0]
[24.23, 20.0, 22.0, 3.33, 2.0]
[32.78, 31.0, 31.0, 3.33, 0.0]
[36.58, 31.0, 35.0, 3.33, 4.0]
[38.48, 35.0, 37.0, 3.33, 2.0]
[41.33, 37.0, 40.0, 3.33, 3.0]
You can see that the x values do not follow the original sequence. Since there's no need to take a chance letting 'y's get associated with the wrong 'x's, lets just force them to stay together.
Here is how I modified your code to keep the ys and xs together.
def ybs(pairs,bs,a)
difference=0.0
xelem=0.0
return pairs.map do |pair|
x,y = pair[0], pair[1]
cb = bs.min_by do |b|
(x-(y-b)*1/a).abs
end
difference = (x-(y-cb)*1/a).abs
[y,x,(y-cb)*1/a,cb,difference]
end
end
a=0.95;
b1=3.33;
b2=5.55;
bs = [b1, b2]
x=[1,3,4,6,9,13,20,22,31,35,37,40];
y=x.collect.with_index{|z,i| i>6 ? z*a+b1 : z*a+b2}
c = x.count-1
pairs = (0..c).collect do |i|
[x[i],y[i]]
end
r = ybs(pairs,bs,a)
r.each do |q|
(0..4).each do |p|
q[p] = q[p].round(2)
end
p q
end
and here is my output:
[6.5, 1.0, 1.0, 5.55, 0.0]
[8.4, 3.0, 3.0, 5.55, 0.0]
[9.35, 4.0, 4.0, 5.55, 0.0]
[11.25, 6.0, 6.0, 5.55, 0.0]
[14.1, 9.0, 9.0, 5.55, 0.0]
[17.9, 13.0, 13.0, 5.55, 0.0]
[24.55, 20.0, 20.0, 5.55, 0.0]
[24.23, 22.0, 22.0, 3.33, 0.0]
[32.78, 31.0, 31.0, 3.33, 0.0]
[36.58, 35.0, 35.0, 3.33, 0.0]
[38.48, 37.0, 37.0, 3.33, 0.0]
[41.33, 40.0, 40.0, 3.33, 0.0]
All of the errors are small, and the bs are correct... they are 5.55 until the 7th row, where they switch to 3.33, as your rule prescribes.

Resources