arraysrubyequality

Ruby array equality independent of order


I have an array of arrays, called guid_pairs:

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

I also have an array, called array_to_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


Solution

  • 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?:

    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.