sorting dynamic multidimensional array - arrays

im tryin to sort a two-dimensional Array in Ruby by the first value, like that:
files_array = Array.new(2) {Array.new}
files_array[0][0] = 42
files_array[1][0] = "/media/js/aefc015sdfsdf0728175535.js42"
files_array[0][1] = 21
files_array[1][1] = "/media/js/aefc015sdfsdf0728175535.js21"
files_array[0][2] = 30
files_array[1][2] = "/media/js/aefc015sdfsdf0728175535.js30"
i tried
files_array.sort!{|a,b| b[0] <=> a[0]}
but it returns:
`sort!': comparison of Array with Array failed (ArgumentError)
This is how i want the array to be sorted:
files_array[0][0] = 21
files_array[1][0] = "/media/js/aefc015sdfsdf0728175535.js21"
files_array[0][1] = 30
files_array[1][1] = "/media/js/aefc015sdfsdf0728175535.js30"
files_array[0][2] = 42
files_array[1][2] = "/media/js/aefc015sdfsdf0728175535.js42"

`sort!': comparison of Array with Array failed (ArgumentError)
This is because a[0] and b[0] are elements of an array of arrays, i.e. they are arrays themselves.
If you did this:
files_array.sort!{|a,b| b[0][0] <=> a[0][0]}
It would work.
Incidentally, this looks like a great example of when an associative array would be a better idea than an array of arrays.
files_hash = {
42 => "/media/js/aefc015sdfsdf0728175535.js42",
21 => "/media/js/aefc015sdfsdf0728175535.js21",
30 => "/media/js/aefc015sdfsdf0728175535.js30"
}
Not only is this a lot clearer in code, but you do away with the need to maintain a sorted 2-dimensional array.

try this it will work for you:
files_array = [[42,"/media/js/aefc015sdfsdf0728175535.js42"],[21,"/media/js/aefc015sdfsdf0728175535.js21"],[30,"/media/js/aefc015sdfsdf0728175535.js30"]]
sorted = files_array.sort { |x,y| x[0] <=> y[0] }
puts sorted
Result:
21
/media/js/aefc015sdfsdf0728175535.js21
30
/media/js/aefc015sdfsdf0728175535.js30
42
/media/js/aefc015sdfsdf0728175535.js42

Related

Concatenating a variable number of arrays in Julia

Suppose there is a variable number of 2D arrays which I want to concatenate into a 3D array:
n = 10 # Number of arrays, can be changed to other integers
arrays = Dict()
for i in 1:n
arrays[i] = rand(2,2)
end
The syntax for concatenating arrays, as far as I know, is:
cat(arr1, arr2, arr3, ..., dims=3)
Since the number of arguments is variable, I can only think of the solution:
3d_array = arr1
for i in 2:n
3d_array = cat(3d_array, arrays[i])
end
But how do I concatenate it in the direction dims=3 with one line only, without for loops, etc.?
given the initial code:
n = 10 #random positive integer
arrays = Dict()
for i in 1:n
arrays[i] = rand(2,2)
end
here are some options:
using cat with splatting:
res1 = cat(values(arrays)...,dims=3) #values(dict) gives an iterable of all values stored
using reduce with cat:
res2 = reduce((x,y)->cat(x,y,dims=3),values(arrays)) #using anonymous function to pass kwargs
Im gonna guess and assume that you also want that the following equality holds true:
arrays[i] == res[:,:,i] # for i in 1:n
there is a problem here, as Dicts are unordered, you can check on the display:
julia> arrays
Dict{Any,Any} with 10 entries:
7 => [0.586479 0.280905; 0.805592 0.737151]
4 => [0.0214868 0.340997; 0.191425 0.271359]
9 => [0.060134 0.939555; 0.0896634 0.455099]
10 => [0.990368 0.214775; 0.224519 0.767086]
2 => [0.578315 0.109518; 0.794717 0.0584819]
3 => [0.106458 0.287653; 0.523525 0.277063]
5 => [0.372227 0.151974; 0.921043 0.238088]
8 => [0.690332 0.14813; 0.771126 0.320432]
⋮ => ⋮
How to solve this? changing the iterator:
cat with ordered splatting:
res3 = cat((arrays[i] for i in 1:n)...,dims=3) #using iterator syntax to return ordered values
reduce with ordered cat:
res4 = reduce((x,y)->cat(x,y,dims=3),(arrays[i] for i in 1:n))
at last, not asked, but my favorite, using broadcasting syntax to put those values on an prealocated array:
res5 = zeros(eltype(arrays[1]),2,2,n) #if you know the size beforehand
res5 = zeros(eltype(arrays[1]),size(arrays[1])...,n) #if you dont know
for i in 1:n
res5[:,:,i] .= arrays[i]
end
You use reduce. The syntax is
reduce((x,y) -> cat(x,y,dims = 3), arrays)

Finding the common value in N number of arrays

I have n number of arrays and I want to work out if there is a common value in these arrays. If I knew the number of arrays I could do something like:
a = [1,2,3]
b = [2,4,5]
c = [2,6,7]
x = a & b & c
x == [2]
However, this isn't possible if you don't know the number of arrays. So far I've come up with this:
array_of_integers = [[1,2,3],[2,4,5]....]
values = []
array_of_integers.each_with_index do |array, index|
values = if index.zero?
array
else
values & array
end
end
# `values` will be an array of common values
However, this doesn't seem very efficient. Is there a better way?
However, this isn't possible if you don't know the number of arrays.
Actually, Enumerable#reduce can help with it:
[[1,2,3], [2,4,5], [2,6,7]].reduce(&:&) # => [2]
&:& looks interesting, but it's just:
[[1,2,3], [2,4,5], [2,6,7]].reduce { |memo, el| memo & el } # => [2]
Or it's also possible to do it as #Jagdeep suggested:
[[1,2,3], [2,4,5], [2,6,7]].reduce(:&) # => [2]

Adding an element of an array with respective element of other arrays

I have multiple array, number can be arbitrary. but the size of all array is same. How do i add each element of with respective element of all the arrays and maybe save it in another array
A1 = [1 2 3 4 5 6]
A2 = [1 2 3 4 5 6]
.
.
.
.
final = [1+1+1+... 2+2+2+.... 3+3+3+3.... 4+4+4.... 5+5+5+5... 6+6+6+6...]
As your arrays are all the same length you can just add the arrays forming a new array.
final = A1+A2
This function searches in your workspace looking for all variables containing capital 'A'. The for loop adds all found variables. If there are other variables containing 'A', other restrictions has to be made.
variables = who %# all variable names from workspace
index = strmatch('A',variables) %# indices matching "A"
newarray = 0
for j = 1:numel(index)
tmp = eval(char(variables(index(j)))); %# store variable in tmp
newarray = newarray + tmp; %# sum
end
If you have an unknown number of A's, you can try something like this:
final = 0
i = 1
while exist(['A' num2str(i)]) == 1 % ['A' num2str(i)] constructs the variable name, eval calls it
final = final + eval(['A' num2str(i)]);
i = i + 1;
end
This should work as long as the variables are stored in the workspace, are of the same length and are named A1, A2, A3, ... A9, A10, ...
Let's say you have this structure (as you write in the comments):
main = struct('err',{1:6,5:10,1:6,1:6},'seg_err',{1:6,5:10,1:6,5:10});
you can convert it to matrix:
m = vertcat(main.seg_err);;
And than take the sum in a simple command:
final = sum(m)
which results:
final =
12 16 20 24 28 32
and thanks to #beaker :)

Ruby how to compare 2D arrays values

I have two question about array of arrays on Ruby :
first, i dont know how to compare this array of arrays
a = [[1,2,3,5] , [1,2,3,6]]
(Output: 11 < 12 )
second , I want to merge them into one long array
a = [[1,2,3] , [4,5,6]]
=> a = [1,2,3,4,5,6]
Thank you.
To get an item with max sum from array you can use this line:
a.max_by {|arr| arr.inject(0, &:+)}
And to get all uniq values from all arrays in parent array, use this line:
[[1,2,3] , [4,5,6]].flatten.uniq
Your first question: Are you trying to compare the sums of the contents of your two arrays? If so you could do the following:
a = [[1,2,3,5],[1,2,3,6]]
a[0].inject(:+) < a[1].reduce(:+)
# returns true
Your second question: a.flatten will combine all of the elements into one array.
I'd recommend reading through the Ruby docs, as things like inject and flatten are explained in great detail.
first , i dont know how to compare this array of arrays a = [[1,2,3,5] , [1,2,3,6]] (try to get the answer 11 < 12 )
You could do it by using
a = [[1,2,3,5] , [1,2,3,6]]
a[0].inject{|sum,x| sum + x } < a[1].inject{|sum,x| sum + x }
Or
a = [[1,2,3,5] , [1,2,3,6]]
a[0].reduce(:+) < a[1].reduce(:+)
You could also use a[0].inject(:+) < a[1].inject(:+). Reduce emphasises Map reduce verbage.
second , i want to merge them into one long array a = [[1,2,3] , [4,5,6]] => a = [1,2,3,4,5,6]
a = [[1,2,3,5] , [1,2,3,6]]
concatenated = a.flatten
or
a = [[1,2,3,5] , [1,2,3,6]]
concatenated = a.reduce(:concat)
or
concatenated = a.reduce(:+)

Convert a cell array of cells to cell arrays of doubles

Let's say, that i have a cell array of cells containing only numeric values. Its name is Q.
Q = { {[0] [1] [0] [238]} }
Q{1}
ans =
[0] [1] [0] [238]
What i would like to do, is to combine all these 4 cells into just one.
In that case, it would be something like the one below:
Q{1}
ans =
0 1 0 238
Any help would be really appreciated.
You have a double-nested cell array:
Q = { {[0] [1] [0] [238]} }
and you need comma-separated lists to transform it into an array. I assume you have multiple cell arrays within Q, so you can use cellfun:
out = cellfun(#(x) [x{:}], Q,'uni',0)
and you get
Q{1} =
[0] [1] [0] [238]
out{1} =
0 1 0 238
For one element this is equivalent to:
Q{1} = [Q{1}{:}]
as the x in the cellfun operation is equivalent to Q{i} where i is the running variable.
But if you you just have this one array in your cell array, consider:
out = cell2mat(Q{:})
as you don't need it to be a cell array at all.
Try doing this:
Q{1} = [Q{1}{:}]

Resources