0

I need to sort a multidimensional array by first line. The first line (array[0][0] to array[0][n-1]) is composed of strings, I need to sort it, and the other lines to follow up...

I already searched a lot and saw how to use the sort function to sort it by column, but didn't found out how to apply it to my problem...
I already solved my problem with a bubble sort who sort the first line, then report the change to the other lines if there's one, but I wondered if there was a better way to do it ?

Creation of the array : array = Array.new(4) { Array.new(var, 0) }

I have something like that in it :

[ [ "A 1", "A 3", "A 2", "A 4" ],
[ 4, 5, 6, 7 ],
[ 2, 2, 2, 2 ],
[ 0.1, 0.2, 0.1, 0.2 ] ]

The expected result would be as followed :

[ [ "A 1", "A 2", "A 3", "A 4" ],
[ 4, 6, 5, 7 ],
[ 2, 2, 2, 2 ],
[ 0.1, 0.1, 0.2, 0.2 ] ]
1
  • Please use English punctuation, not the French one, when you write in English. Commented Feb 7, 2019 at 11:12

2 Answers 2

2

You can use Array#transpose and Enumerable#sort_by to handle this like so:

 arr = [ [ "A 1", "A 3", "A 2", "A 4" ],
         [ 4, 5, 6, 7 ],
         [ 2, 2, 2, 2 ],
         [ 0.1, 0.2, 0.1, 0.2 ] ]

Array#transpose turns rows into columns:

arr.transpose
#=> [["A 1", 4, 2, 0.1],
#    ["A 3", 5, 2, 0.2],
#    ["A 2", 6, 2, 0.1],
#    ["A 4", 7, 2, 0.2]]

Then we just need to sort by the first column values sort_by(&:first):

arr.transpose.sort_by(&:first)
#=> [["A 1", 4, 2, 0.1],
#    ["A 2", 6, 2, 0.1],
#    ["A 3", 5, 2, 0.2],
#    ["A 4", 7, 2, 0.2]]

Then we just transpose back again:

arr.transpose.sort_by(&:first).transpose
#=> [["A 1", "A 2", "A 3", "A 4"],
#    [4, 6, 5, 7],
#    [2, 2, 2, 2],
#    [0.1, 0.1, 0.2, 0.2]]

The same could be achieved by zipping the Arrays together like so: (but the former seems like a better choice)

arr.reduce(&:zip).sort_by {|a| a.flatten!.first}.transpose
#=> [["A 1", "A 2", "A 3", "A 4"],
#    [4, 6, 5, 7],
#    [2, 2, 2, 2],
#    [0.1, 0.1, 0.2, 0.2]]
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot, i didn't even think about that !
0

Less Ruby'ish approach:

sorted = arr.first.sort
# => ["A 1", "A 2", "A 3", "A 4"] 
order_arr = arr.first.map { |x| sorted.index(x) }
#  => [0, 2, 1, 3]
arr.map { |a| order_arr.map { |x| a[x] } }
# => [["A 1", "A 2", "A 3", "A 4"],
#     [4, 6, 5, 7],
#     [2, 2, 2, 2],
#     [0.1, 0.1, 0.2, 0.2]]

2 Comments

You could make this exact concept more "rubyish" by replacing the first 2 lines with sorted = arr.first.each_with_index.sort_by(&:first).map(&:last) and replacing arr.map { |a| order_arr.map { |x| a[x] } } with arr.map { |a| a.values_at(*sorted) }
@engineersmnky values_at also works for arrays, not only hashes, very nice to know, thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.