Advanced array sorting

Hi,

Here’s an example of an array I want to sort:

ary = [[0.2, “b”], [0.4, “b”], [0.2, “c”], [0.0, “c”], [0.5, “a”], [0.7,
“d”], [0.7, “a”]]

The array should be sorted by the first element of every ‘subarray’. I
do this with ary.sort_by{|element|element[0]} method. This works fine,
but when two values are equal (which happens twice in this example) I
need an extra condition to sort these equal values.

The sorted array should look like:

[[0.0, “c”], [0.2, “c”], [0.2, “b”], [0.4, “b”], [0.5, “a”], [0.7, “a”],
[0.7, “d”]]

For the case of 0.7: The arrays that contain as second element “a” and
“d”. There’s another array with “a”, but no other array with element
“d”. This means that the array of “a” should be sorted before “d”.

For the case of 0.2: The second element of these arrays are “c” and “d”.
These second element both occur in another array. The value of these
second array should decide how the sorting goes. So “b” before “c”.

I’m having trouble figuring this out. I hope I’ve been clear.

I suppose you want to sort by the first element, then by the second.

You can pass a custom comparator to sort like this:

ary = [[0.2, “c”], [0.4, “b”], [0.2, “b”], [0.0, “c”], [0.5, “a”], [0.7,
“d”], [0.7, “a”]]
ary.sort!{|x,y|
x[0]==y[0] ? x[1]<=>y[1] : x[0]<=>y[0]
}

Dansei Yuuki wrote in post #1183025:

I suppose you want to sort by the first element, then by the second.

Not quiet correct, I want to use the second element to see which other
submatrix also got this as second element. Then I want to use the first
element of these other submatrices to do the compare function.

Your solution gives:

[[0.0, “c”], [0.2, “b”], [0.2, “c”], [0.4, “b”], [0.5, “a”], [0.7, “a”],
[0.7, “d”]]

While it should be:

[[0.0, “c”], [0.2, “c”], [0.2, “b”], [0.4, “b”], [0.5, “a”], [0.7, “a”],
[0.7, “d”]]

If someone could tell me if this is possible with the .sort_by method
would also be a help.

Thanks regis!

In the meantime I coded something that does the job in 50 lines. That’s
why I asked for some advice. Will use your solution now.

If someone could tell me if this is possible with the .sort_by method
would also be a help.

Use group_by for extract tuples by second value, sort the sub-lists,
and compact each sub-list as one list:

ary = [
[0.2, “c”], [0.4, “b”], [0.2, “b”], [0.0, “c”],
[0.5, “a”], [0.7,“d”], [0.7, “a”]
]

ary.sort_by {|(v,k)| v}.
group_by {|a| a.last}.
each_with_object({}) {|(k,elem),h| h[k]=elem.sort }.
to_a.
map {|key,l| l}.flatten(1)

=> [[0.0, “c”], [0.2, “c”], [0.2, “b”], [0.4, “b”], [0.5, “a”], [0.7,
“a”], [0.7, “d”]]

ary = [
[1.2, “c”], [1.4, “b”], [0.2, “b”], [0.0, “c”],
[0.5, “a”], [0.7,“d”], [0.7, “a”]
]
ary.sort_by {|(v,k)| v}.
group_by {|a| a.last}.
each_with_object({}) {|(k,elem),h| h[k]=elem.sort }.
to_a.
map {|key,l| l}.flatten(1)

=> [[0.0, “c”], [1.2, “c”], [0.2, “b”], [1.4, “b”], [0.5, “a”], [0.7,
“a”], [0.7, “d”]]

ary = [
[1.2, “c”], [1.4, “b”], [0.2, “b”], [0.0, “c”],
[0.5, “a”], [0.7,“d”], [0.7, “a”]
]