Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

is there a shorter way to compare these 2 objects?

0 views
Skip to first unread message

Lowell Kirsh

unread,
Aug 17, 2005, 11:13:35 PM8/17/05
to
I have a class called foo and I want to make it comparable so that I can
sort arrays of Foo. Here is the class:

class Foo
attr_accessor :a, :b, :c, :d
def <=>(rhs); (see below); end
end

I'm assuming that the a,b,c, and d field are each Comparable. To compare
2 Foos, we first look at the a's and if they're not the same, we return
the result of their comparison. If they are the same, we continue to
compare the b's, and if they're the same we compare the c's, and so on
until we compare the last field. So for my definition of <=> I have the
following, which works, but I'd like something better/shorter:

if (@a <=> rhs.a) != 0
@a <=> rhs
elsif (@b <=> rhs.b) != 0
@b <=> rhs.b
elsif ....

Is there a more concise way of doing this? I know this code isn't the
ugliest, but something in my gut tells me there's got to be a better
way. Especially if we have more than 4 variables.

lowell

James Edward Gray II

unread,
Aug 17, 2005, 11:33:42 PM8/17/05
to

On Aug 17, 2005, at 10:16 PM, Lowell Kirsh wrote:

> I have a class called foo and I want to make it comparable so that
> I can sort arrays of Foo. Here is the class:
>
> class Foo
> attr_accessor :a, :b, :c, :d
> def <=>(rhs); (see below); end
> end
>
> I'm assuming that the a,b,c, and d field are each Comparable. To
> compare 2 Foos, we first look at the a's and if they're not the
> same, we return the result of their comparison. If they are the
> same, we continue to compare the b's, and if they're the same we
> compare the c's, and so on until we compare the last field. So for
> my definition of <=> I have the following, which works, but I'd
> like something better/shorter:

def <=>( other )
[@a, @b, @c, @d] <=> [other.a, other.b, other.c, other.d]
end

Arrays are Comparable and they compare each of their contents in order.

Hope that helps.

James Edward Gray II

Robert Klemme

unread,
Aug 18, 2005, 4:40:36 AM8/18/05
to

Here are some other possible implementations using #inject... :-)

require 'enumerator'

Foo = Struct.new :a,:b,:c,:d

class Foo
include Comparable

def <=>(o)
members.inject(0) do |cmp,field|
return cmp unless cmp == 0
send(field) <=> o.send(field)
end
end

# alternative
def <=>(o)
cmp = 0
each_pair do |field, val|
cmp = val <=> o.send(field)
return cmp unless cmp == 0
end
cmp
end

# alternative
def <=>(o)
to_enum(:each_pair).inject(0) do |cmp,(field, val)|
cmp = val <=> o.send(field)
return cmp unless cmp == 0
end
end

end

>> f1 = Foo.new 1,2,3,4
=> #<struct Foo a=1, b=2, c=3, d=4>
>> f2 = Foo.new 1,2,3,3
=> #<struct Foo a=1, b=2, c=3, d=3>
>> puts f1 <=> f2
1
=> nil


Kind regards

robert

Kroeger Simon (ext)

unread,
Aug 18, 2005, 4:47:13 AM8/18/05
to

> From: James Edward Gray II [mailto:ja...@grayproductions.net]

>
> def <=>( other )
> [@a, @b, @c, @d] <=> [other.a, other.b, other.c, other.d]
> end
>
> Arrays are Comparable and they compare each of their contents
> in order.
>
> Hope that helps.
>
> James Edward Gray II

not as elegant but without allocating two arrays:

def <=>( other )

(@a <=> other.a).nonzero? ||
(@b <=> other.b).nonzero? ||
(@c <=> other.c).nonzero? ||
(@d <=> other.d)
end

cheers

Simon


James Edward Gray II

unread,
Aug 18, 2005, 9:52:43 AM8/18/05
to
On Aug 17, 2005, at 10:33 PM, James Edward Gray II wrote:

> Arrays are Comparable...

I misspoke a little here. Arrays are NOT Comparable, but the DO
implement <=>(), which is all you need here.

James Edward Gray II


Lowell Kirsh

unread,
Aug 18, 2005, 6:55:01 PM8/18/05
to
Cool, I didn't realize nonzero? returned anything useful other than
truth/falsity.

Lowell Kirsh

unread,
Aug 18, 2005, 6:55:35 PM8/18/05
to
James Edward Gray II wrote:
> def <=>( other )
> [@a, @b, @c, @d] <=> [other.a, other.b, other.c, other.d]
> end

Great, this is *exactly* what I was looking for :)

Lowell Kirsh

unread,
Aug 18, 2005, 6:56:25 PM8/18/05
to
Those solutions are definitely cool but I find James' to be more
readable so that's what I'll use.

Robert Klemme

unread,
Aug 19, 2005, 3:26:59 AM8/19/05
to
Lowell Kirsh wrote:
> Those solutions are definitely cool but I find James' to be more
> readable so that's what I'll use.

Yes definitely! I just had some fun playing around with this. :-)

robert

0 new messages