Сравнение двух массивов, игнорирующих порядок элементов в Ruby
Мне нужно проверить, содержат ли два массива одни и те же данные в любом порядке.
Используя мнимый метод compare
, я хотел бы сделать:
arr1 = [1,2,3,5,4]
arr2 = [3,4,2,1,5]
arr3 = [3,4,2,1,5,5]
arr1.compare(arr2) #true
arr1.compare(arr3) #false
Я использовал arr1.sort == arr2.sort
, который, похоже, работает, но есть ли лучший способ сделать это?
Ответы
Ответ 1
Сортировка массивов до их сравнения - O (n log n). Более того, как указывает Виктор, вы столкнулись с проблемой, если массив содержит не сортируемые объекты. Быстрее сравнивать гистограммы, O (n).
Вы найдете Enumerable#frequency в Facets, но реализуйте его самостоятельно, что довольно просто, если вы предпочитаете избегать добавления дополнительных зависимостей
require 'facets'
[1, 2, 1].frequency == [2, 1, 1].frequency
#=> true
Ответ 2
Самый простой способ - использовать пересечения:
@array1 = [1,2,3,4,5]
@array2 = [2,3,4,5,1]
Итак, утверждение
@array2 & @array1 == @array2
Будет true
. Это лучшее решение, если вы хотите проверить, содержит ли array1
array2
или наоборот (это другое). Вы также не занимаетесь своими массивами или не меняете порядок предметов. Вы также можете сравнить длину обоих массивов, если хотите, чтобы они были одинаковыми по размеру.
Это также самый быстрый способ сделать это (исправьте меня, если я ошибаюсь)
Ответ 3
Если вы знаете, что в любом из массивов нет повторений (т.е. все элементы уникальны или вам все равно), использование наборов является прямым и читаемым:
Set.new(array1) == Set.new(array2)
Ответ 4
Вы можете реально реализовать этот #compare
метод с помощью обезьяны Patching класса Array, как это:
class Array
def compare(other)
sort == other.sort
end
end
Имейте в виду, что исправление обезьян редко считается хорошей практикой, и вы должны быть осторожны при его использовании.
Вероятно, есть лучший способ сделать это, но это то, что пришло на ум. Надеюсь, поможет!
Ответ 5
Самый элегантный способ, который я нашел:
arr1 = [1,2,3,5,4]
arr2 = [3,4,2,1,5]
arr3 = [3,4,2,1,5,5]
(arr1 - arr2).empty?
=> true
(arr3 - arr2).empty?
=> false
Ответ 6
Вы можете открыть класс array
и определить способ, подобный этому.
class Array
def compare(comparate)
to_set == comparate.to_set
end
end
arr1.compare(arr2)
irb => true
ИЛИ просто используйте
arr1.to_set == arr2.to_set
irb => true
Ответ 7
Вот версия, которая будет работать с несортируемыми массивами
class Array
def unordered_hash
unless @_compare_o && @_compare_o == hash
p = Hash.new(0)
each{ |v| p[v] += 1 }
@_compare_p = p.hash
@_compare_o = hash
end
@_compare_p
end
def compare(b)
unordered_hash == b.unordered_hash
end
end
a = [ 1, 2, 3, 2, nil ]
b = [ nil, 2, 1, 3, 2 ]
puts a.compare(b)
Ответ 8
Я опаздываю, но в этом случае с ruby 2.3.x:
arr1 = [1,2,3,5,4]
arr2 = [3,4,2,1,5]
arr3 = [3,4,2,1,5,5]
Я использую:
a - b == b - a && a.length == b.length
=> true
a - c == c - a && a.length == c.length
=> false
Когда я просто хочу сравнить, два массива имеют одинаковый контент, я использую:
a - b == b - a
=> true
a - c == c - a
=> true
Извините за мой плохой английский!