Равенство массивов Ruby - PullRequest
       11

Равенство массивов Ruby

2 голосов
/ 15 июня 2011

У меня есть массив массивов, называемый guid_pairs:

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

У меня также есть массив, называемый array_to_check:

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

Как определить,массив guid_pairs имеет элемент, равный array_to_check.Равенство не должно учитывать положение элементов массива.

В этом примере проверка должна возвращать true, поскольку guid_pairs содержит элемент ['a','b','c'], который соответствует ['c','a','b'].

Я пробовал это, но, кажется, всегда возвращает false, даже если он должен вернуть true:

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

Я использую Ruby 1.9.2

Ответы [ 6 ]

8 голосов
/ 15 июня 2011

В стандартной библиотеке есть набор классов , и использование наборов точно соответствует вашим намерениям:

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) }

Это оставит соответствующий элемент элемента aa в the_match,Если вас интересует только существование, вы можете просто проверить правдивость the_match;или используйте any? (спасибо за напоминание Майкла Коля, я часто забываю о некоторых вещах в Enumerable):

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

Нет трюков, нет магии, и использование Set делаетясно, что вы на самом деле сравниваете массивы как наборы.


Кстати, ваше попытанное решение:

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

не работает, потому что массивы сравнивают поэлементноэлемент по порядку, поэтому два массива равны тогда и только тогда, когда они имеют одинаковые элементы в одном и том же порядке.Документация для eql? может быть более понятной:

Возвращает true, если self и other являются одним и тем же объектом или являются массивами с одинаковым содержимым.

Но документация == хороша и понятна:

Два массива равны, если они содержат одинаковое количество элементов и если каждый элемент равен (согласно Object. ==) соответствующий элемент в другом массиве.

Мы можем посмотреть Object # eql? для некоторого пояснения:

Экл?Метод возвращает true, если obj и anObject имеют одно и то же значение.Используется Hash для проверки членов на равенство.Для объектов класса Object, eql?является синонимом ==.Подклассы обычно продолжают эту традицию, но есть исключения.

Так что == и eql? должны вести себя одинаково, если нет веских причин для их отличия.

4 голосов
/ 15 июня 2011

Чтобы увидеть, содержат ли два массива одинаковые элементы, независимо от порядка, вы можете использовать операцию XOR (исключая или).Он вернет массив, который содержит только элементы, которые находятся в одном массиве, а не в другом.Если длина XOR равна нулю, то входные массивы содержат одинаковые элементы.

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

guid_pairs.any? { |pair| xor(pair, array_to_check).length != 0 }
1 голос
/ 23 декабря 2012

для равенства двух массивов A и B, которые я обычно использую:

if(((A-B) + (B-A)).blank?)
    puts "equal"
else
    "unequal"
end
1 голос
/ 15 июня 2011

Возможным решением является сортировка массивов перед сравнением (или даже во время сравнения):

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

Обратите внимание, что это не может быть оптимальным решением - было бы более уместно отсортировать ваши массивы (тем не менее, они являются наборами в вашем случае использования).

0 голосов
/ 15 июня 2011

Три решения:

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

Без определения метода (по совету Джоши):

  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 голосов
/ 15 июня 2011

Вы можете использовать следующее:

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