[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: Compare Array Values?

Darshan.Ishaya

11/23/2006 3:44:00 AM

The Coolest Way:

def same_elems?(array1, array2)
return false unless array1.length == array2.length

compare = Proc.new do |x,y|
if (x.class == y.class)
x <=> y
else
x.class.to_s <=> y.class.to_s
end
end

return array1.sort(&compare) == array2.sort(&compare)
end

Ruby sure is fun. Like I said, I'm new to Ruby, so I'm still getting a
kick out of all this stuff. I'm pretty sure this works (i.e, meets all
of your criteria), and man do I think it's cool that you can do this.
Remember I said you could pass a block to sort()? Well, I just did
what I wanted (I'm not used to being ABLE to do what I want, Ruby seems
to make it way easier to just tell it to do what you want it to.)

I guess it'll work for any two arrays filled with objects of any
classes that have <=> defined. That should be most, I think. I just
tell sort() to compare with <=> if the objects to be compared are of
the same class, and if not, sort by putting the one whose class name
comes first alphabetically (converting their class names to Strings and
comparing those with <=>). So you get a sorted array with, e.g. Arrays
first, then Fixnums, then Stings, then Symbols, or whatever, but
classes in order, and in order within the classes.

It's conceptually simple, but I have no idea how it compares in speed
to the other ways. Can anyone give me a tip on a good way to
benchmark?

Darshan


3 Answers

dblack

11/23/2006 3:57:00 AM

0

Darshan.Ishaya

11/23/2006 4:53:00 AM

0

Ah, thanks. I knew it would only work for classes with <=> defined, but
I was naively assuming all important classes did. (I've only been
playing with Ruby for a couple of weeks.) I didn't realize a class as
important as Symbol didn't have it.

I could try a slightly better, but probably similarly flawed:

def same_elems?(array1, array2)
return false unless array1.length == array2.length

compare = Proc.new do |x,y|
if (x.class == y.class)
if x.respond_to?('<=>')
x <=> y
else
x.to_s <=> y.to_s
end
else
x.class.to_s <=> y.class.to_s
end
end

return array1.sort(&compare) == array2.sort(&compare)
end

I'm now naively assuming all important classes implement to_s ; )

At least judging by this:

darshan@shadow ~ $ ri -T "<=>" | awk '{gsub(/<=>,/,"<=>\n");print}' |
grep "<=>" | wc -l
25
darshan@shadow ~ $ ri -T "to_s" | awk '{gsub(/to_s,/,"to_s\n");print}' |
grep "to_s$" | wc -l
116

it'll have a much better chance (almost 5 x) of working. (Sorry, I
haven't switched to Ruby one-liners yet; I'm sure I will soon.)

I guess it all depends on the application, and what classes are going to
be in the arrays. I sure had fun playing with it though. I'm so stoked
about Ruby.

Darshan

dblack@wobblini.net wrote:
> Hi --
>
> On Thu, 23 Nov 2006, Darshan.Ishaya wrote:
>
>> The Coolest Way:
>>
>> def same_elems?(array1, array2)
>> return false unless array1.length == array2.length
>>
>> compare = Proc.new do |x,y|
>> if (x.class == y.class)
>
> You'd probably want to throw in a "and if x.respond_to?('<=>')".
>
>> x <=> y
>> else
>> x.class.to_s <=> y.class.to_s
>
> The problem there is that it can't sort *within* a class that doesn't
> have <=> (and if it did, it would have sorted it that way :-) So, for
> example:
>
> p [:a,:b].sort(&compare) # => [:a,:b]
> p [:b,:a].sort(&compare) # => [:b,:a]
>
>
> David
>

Edwin Fine

11/23/2006 5:49:00 AM

0

I modified a previous poster's program that used hashes (good idea!).
Now there's only one hash, which counts the number of identical keys
instead of actually storing the values. I then decrement the hash values
for each key in b. If a and b are equal, all values in the hash should
be 0. I also immediately reject as non-equal two arrays of different
sizes. Seems to work for his test cases (and some I added), and I guess
is probably smaller and faster. Are there any holes in this solution?

def content_eq a, b
return false if a.length != b.length
ah = Hash.new {|h,k| h[k] = 0 }
a.each {|x| ah[x] += 1 }
b.each {|x| ah[x] -= 1 }
# Not equal if any non-zero values
not ah.values.detect {|v| v != 0 }
end

pairs = [
[ [1,2,3,4,"abc"], [2,3,1,"abc",4] ],
[ [1,2,3], [1,1,2,3] ],
[ [1,2,3,nil], [nil, nil, nil, 1,2,1,3,2] ],
[ [], [] ],
[ [], [nil] ],
[ [/^$/], [/^$/] ],
[ [/^$/], [/^/] ],
[ [nil, nil, nil, nil], [nil, nil, nil, nil] ],
]

pairs.each{|a,b| puts "content_eq(#{ a.inspect }, #{ b.inspect }) #=> #{
content_eq a, b }"}

----
content_eq([1, 2, 3, 4, "abc"], [2, 3, 1, "abc", 4]) #=> true
content_eq([1, 2, 3], [1, 1, 2, 3]) #=> false
content_eq([1, 2, 3, nil], [nil, nil, nil, 1, 2, 1, 3, 2]) #=> false
content_eq([], []) #=> true
content_eq([], [nil]) #=> false
content_eq([/^$/], [/^$/]) #=> true
content_eq([/^$/], [/^/]) #=> false
content_eq([nil, nil, nil, nil], [nil, nil, nil, nil]) #=> true

--
Posted via http://www.ruby-....