Try this: array.sort { |x,y| x.a == y.a ? x.b <=> y.b : x.a <=> y.a }
Or overide the <=> method in your struct.
···
2011/7/1 Iñaki Baz Castillo <ibc@aliax.net>
2011/7/1 Iñaki Baz Castillo <ibc@aliax.net>:
> I expected that the following could work:
>
> array.sort_by{|entry| entry.a or entry.b}
>
> but it generates:
>
> [kk1, kk2, kk3, kk4]
>
> so obviously it does not work. I'm not very used to Enumerable.sort_by
> method, any tip please?
Maybe it would be better to use "class KK" rather than an struct, and
then define <=> method for KK class (and include Enumerable module)?
Structs return classes already (this is why you can inherit from them in the
form `class A < Struct.new(:a,:b)`). You can pass Struct.new a block, and it
will be evaluated within the context of the struct you are creating:
KK = Struct.new(:a,:b) do
def <=>(kk)
if a < kk.a
-1
elsif a > kk.a
1
else
kk.b <=> b
end
end
end
# Elements with minor :a must be first.
# If two elements have same :a, then order based on higher :b.
# The result should be:
[kk1, kk2, kk4, kk3] == array.sort # => true
···
On Fri, Jul 1, 2011 at 5:55 AM, Iñaki Baz Castillo <ibc@aliax.net> wrote:
2011/7/1 Iñaki Baz Castillo <ibc@aliax.net>:
> I expected that the following could work:
>
> array.sort_by{|entry| entry.a or entry.b}
>
> but it generates:
>
> [kk1, kk2, kk3, kk4]
>
> so obviously it does not work. I'm not very used to Enumerable.sort_by
> method, any tip please?
Maybe it would be better to use "class KK" rather than an struct, and
then define <=> method for KK class (and include Enumerable module)?
Sorry code must be array.sort { |x,y| x.a == y.a ? -(x.b <=> y.b) : x.a <=>
y.a }
···
2011/7/1 Gunther Diemant <g.diemant@gmx.net>
Try this: array.sort { |x,y| x.a == y.a ? x.b <=> y.b : x.a <=> y.a }
Or overide the <=> method in your struct.
2011/7/1 Iñaki Baz Castillo <ibc@aliax.net>
2011/7/1 Iñaki Baz Castillo <ibc@aliax.net>:
> I expected that the following could work:
>
> array.sort_by{|entry| entry.a or entry.b}
>
> but it generates:
>
> [kk1, kk2, kk3, kk4]
>
> so obviously it does not work. I'm not very used to Enumerable.sort_by
> method, any tip please?
Maybe it would be better to use "class KK" rather than an struct, and
then define <=> method for KK class (and include Enumerable module)?
Really thanks to all for your responses, I will try them
···
2011/7/1 Josh Cheek <josh.cheek@gmail.com>:
Structs return classes already (this is why you can inherit from them in the
form `class A < Struct.new(:a,:b)`). You can pass Struct.new a block, and it
will be evaluated within the context of the struct you are creating:
KK = Struct.new(:a,:b) do
def <=>(kk)
if a < kk.a
-1
elsif a > kk.a
1
else
kk.b <=> b
end
end
end
Note that entries must be ordered by smaller :a and, in case of same
:a, by higher :b. So the last "e.b" should be changed to something
else. Trying it right now.
Thanks a lot.
···
2011/7/1 Robert Klemme <shortcutter@googlemail.com>:
Oh, my mistake. I am sorry. So that would be (for numeric b):
array.sort_by {|e| [e.a, -e.b]}
And then
KK = Struct.new :a,:b do
include Comparable
def <=>(o)
cmp = a <=> o.a
cmp == 0 ? o.b <=> b : cmp
end
end
Cheers
robert
···
On Fri, Jul 1, 2011 at 1:22 PM, Iñaki Baz Castillo <ibc@aliax.net> wrote:
2011/7/1 Robert Klemme <shortcutter@googlemail.com>:
array.sort_by {|e| [e.a, e.b]}
Note that entries must be ordered by smaller :a and, in case of same
:a, by higher :b. So the last "e.b" should be changed to something
else. Trying it right now.
I recommend selecting the most straightforward one. Are there any solutions
where you look at them and they are so obvious as to seem mundane? Later
when you look at this code, you'll be appreciative of code like that.
···
On Fri, Jul 1, 2011 at 6:30 AM, Iñaki Baz Castillo <ibc@aliax.net> wrote:
2011/7/1 Gunther Diemant <g.diemant@gmx.net>:
> Nice. Little mistake (same as mine). Code should be array.sort_by { |e|
> [e.a, -e.b] }
Yeah
So I've lot of solutions right now, and all of them work
I'll do some benchmarks and select the fastest one.
Really thanks to all, this community is really impresive.
The efficiency depends on how expensive it is to compute the key of the elements. If the computation is non-trivial, then Array#sort_by would be much faster because it caches the keys before the sort so that no unnecessary computation is done (i.e., the key of each element is computed exactly once).
If, like it is in your case, the computation only involves several Fixnum comparisons, Array#sort_by will most likely be slower as it needs to allocate (cache) the key set prior to the actual sorting.
For example, there should be a difference if the accessors themselves are expensive. Something like:
def a
sleep 0.01 @a
end
As a side note, this idiom used by Array#sort_by is known as the Schwartzian transform in the Perl world.
···
On 7/1/2011 7:30 AM, Iñaki Baz Castillo wrote:
I'll do some benchmarks and select the fastest one.
I recommend selecting the most straightforward one. Are there any solutions
where you look at them and they are so obvious as to seem mundane? Later
when you look at this code, you'll be appreciative of code like that.
Thanks. However in my case the class is a Struct and I add no
complexity to accessor. In fact I just use:
KK = Struct.new(:a, :b)
kk1 = KK.new(10,20)
···
2011/7/1 Su Zhang <su.comp.lang.ruby@gmail.com>:
The efficiency depends on how expensive it is to compute the key of the
elements. If the computation is non-trivial, then Array#sort_by would be
much faster because it caches the keys before the sort so that no
unnecessary computation is done (i.e., the key of each element is computed
exactly once).
If, like it is in your case, the computation only involves several Fixnum
comparisons, Array#sort_by will most likely be slower as it needs to
allocate (cache) the key set prior to the actual sorting.
For example, there should be a difference if the accessors themselves are
expensive. Something like: