开发者

Ruby array equality

开发者 https://www.devze.com 2023-03-13 13:35 出处:网络
I have an array of arrays, called guid_pairs: [[\'a\',\'b\',\'c\'],[\'c\',\'g\'],[\'z\',\'f\',\'b\']] I also have an array, called array_t开发者_如何学Goo_check:

I have an array of arrays, called guid_pairs:

[['a','b','c'],['c','g'],['z','f','b']]

I also have an array, called array_t开发者_如何学Goo_check:

['c','a','b']

How can I determine if the array guid_pairs has an element that is equal to array_to_check. Equality should not consider the position of the array elements.

In this example, the check should return true because guid_pairs contains the element ['a','b','c'], which matches ['c','a','b'].

I have tried this, but it seems to always return false even when it should return true:

guid_pairs.any?{|pair| pair.eql?(array_to_check)}

I am using Ruby 1.9.2


There is a set class in the standard library and using sets nicely matches your intent:

require 'set'

a  = ['c','a','b']
aa = [['a','b','c'],['c','g'],['z','f','b']]

find_this = Set.new(a)
the_match = aa.find { |x| find_this == Set.new(x) }

That will leave the matching element element of aa in the_match. If you're only interested in existence then you can simply check the truthiness of the_match; or use any? (thanks for the reminder Michael Kohl, I often forget about some of the things in Enumerable):

aa.any? { |x| find_this == Set.new(x) }

No tricks, no magic, and using Set makes it clear that you are, in fact, comparing the arrays as sets.


BTW, your attempted solution:

guid_pairs.any? { |pair| pair.eql?(array_to_check) }

doesn't work because arrays compare element-by-element in order so two arrays are equal if and only if they have equal elements in the same order. The documentation for eql? could be clearer:

Returns true if self and other are the same object, or are both arrays with the same content.

But the == documentation is nice and clear:

Two arrays are equal if they contain the same number of elements and if each element is equal to (according to Object.==) the corresponding element in the other array.

We can look to Object#eql? for some clarification though:

The eql? method returns true if obj and anObject have the same value. Used by Hash to test members for equality. For objects of class Object, eql? is synonymous with ==. Subclasses normally continue this tradition, but there are exceptions.

So == and eql? should behave the same way unless there is a good reason for them to be different.


To see if two arrays contain the same elements, regardless of order, you can use the XOR (exclusive or) operation. It will return an array which contains only elements that are in one array and not the other. If the length of the XOR is zero then the input arrays contain the same elements.

def xor(a, b)
  (a | b) - (a & b)
end

guid_pairs.any? { |pair| xor(pair, array_to_check).length != 0 }


A possible solution is to sort the arrays before comparing (or even during comparing):

guid_pairs.any?{|pair| pair.sort.eql?(array_to_check.sort)}

Note that this may not be an optimal solution - it would be more appropriate to have your arrays sorted (nevertheless they are sets in your use case).


for equality of two arrays A and B i normally use:

if(((A-B) + (B-A)).blank?)
    puts "equal"
else
    "unequal"
end


You can use the following:

sorted_array_to_check = array_to_check.sort
guid_pairs.any?{|pair| pair.sort.eql?(sorted_array_to_check)}


Three solutions:

class Array
  def check1 other; other.any?{|e| self - e == e - self} end
  def check2 other; other.any?{|e| self | e == self and e | self == e} end
  def check3 other; other.any?{|e| self & e == self and e & self == e} end
end
array_to_check.check1(guid_pairs) # => true
array_to_check.check2(guid_pairs) # => true
array_to_check.check3(guid_pairs) # => true

Without defining a method (following Josha's suggestion):

  array_to_check.instance_eval{guid_pairs.any?{|e| self - e == e - self}} # => true
  array_to_check.instance_eval{guid_pairs.any?{|e| self | e == self and e | self == e}} # => true
  array_to_check.instance_eval{guid_pairs.any?{|e| self & e == self and e & self == e}} # => true
0

精彩评论

暂无评论...
验证码 换一张
取 消