Let’s say I have an array, each element of which is a 2-dimensional array
of ints.

I want to sort with the first element in the 2D array taking precedence,
but using the second as a tiebreaker.

So far, I haven’t come up with a nice idiom that doesn’t seem a bit kludgy:
What I tried was to do something like:
x.sort {|a,b| a[0]<=>b[0] || a[1]<=>b[1]}
but 0 is not false in Ruby so this doesn’t work.

x.sort {|a,b| 2*(a[0]<=>b[0]) + (a[1]<=>b[1])}
works, but is non-intuitive and not pretty.

Does anyone have a nice clean rubyesque idiom for this?

Let’s say I have an array, each element of which is a 2-dimensional array
of ints.

I want to sort with the first element in the 2D array taking precedence,
but using the second as a tiebreaker.

So far, I haven’t come up with a nice idiom that doesn’t seem a bit kludgy:
What I tried was to do something like:
x.sort {|a,b| a[0]<=>b[0] || a[1]<=>b[1]}
but 0 is not false in Ruby so this doesn’t work.

x.sort {|a,b| 2*(a[0]<=>b[0]) + (a[1]<=>b[1])}
works, but is non-intuitive and not pretty.

Does anyone have a nice clean rubyesque idiom for this?

Rubyesque idiom? Probably not, but this is readable:

y = x.sort{|a,b|
if (result = a[0]<=>b[0]) != 0
result
else
a[1]<=>b[1]
end
}

···

On Tuesday 10 September 2002 01:35 pm, Brett Williams wrote:

Let’s say I have an array, each element of which is a 2-dimensional array
of ints.

I want to sort with the first element in the 2D array taking precedence,
but using the second as a tiebreaker.

So far, I haven’t come up with a nice idiom that doesn’t seem a bit kludgy:
What I tried was to do something like:
x.sort {|a,b| a[0]<=>b[0] || a[1]<=>b[1]}
but 0 is not false in Ruby so this doesn’t work.

x.sort {|a,b| 2*(a[0]<=>b[0]) + (a[1]<=>b[1])}
works, but is non-intuitive and not pretty.

Does anyone have a nice clean rubyesque idiom for this?

Let’s say I have an array, each element of which is a 2-dimensional array
of ints.

I want to sort with the first element in the 2D array taking precedence,
but using the second as a tiebreaker.
[snip]
You can use Numeric’s nonzero? e.g.

I was wrong. Interesting behaviour - nice but confusing - I would have
thought that what with operators being mostly implemented as methods,
the result of nonzero? would be returned instead of the result of
a[0]<=>b[0]. Is there a definitive statement of which operators/methods
modify the “last expression executed”?

I was wrong. Interesting behaviour - nice but confusing - I would have
thought that what with operators being mostly implemented as methods,
the result of nonzero? would be returned instead of the result of
a[0]<=>b[0]. Is there a definitive statement of which operators/methods
modify the “last expression executed”?

Historically, nonzero? was introduced for very this kind of sort (what
is the correct name?). But Array#<=> was introduced in no time after
nonzero? was. Tadayoshi Funaba, who is the inventor of nonzero? and
Array#<=>, said that that Array#<=> might obsolets nonzero?. He
thought that a user however could choose favorite one [ruby-list:8546].
I prefer Array#<=> way.

In 1.7.x, we can do
x.sort_by{|a| [a[1],a[2],a[0]]}

instead of
x.sort{|a,b| [a[1],a[2],a[0]] <=> [b[1],b[2],b[0]]}

and the former is faster than the latter because sort_by implements
Schwartzian transform(*1) in C.

sort_by in Ruby is defined in shim(*2) for 1.6.x as follows:
module Enumerable
def sort_by
ary = map { |i| [yield(i), i] }
ary.sort! { |a, b| a[0] <=> b[0] }
ary.map! { |i| i[1] }
end
end