Сравнение двух массивов, игнорирующих порядок элементов в Ruby - PullRequest
48 голосов
/ 01 февраля 2012

Мне нужно проверить, содержат ли два массива одинаковые данные в любом порядке. Используя мнимый метод 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, который, кажется, работает, но есть ли лучший способ сделать это?

Ответы [ 7 ]

36 голосов
/ 01 февраля 2012

Самый простой способ - использовать пересечения:

@array1 = [1,2,3,4,5]
@array2 = [2,3,4,5,1]

Итак, утверждение

@array2 & @array1 == @array2

будет true. Это лучшее решение, если вы хотите проверить, содержит ли array1 array2 или наоборот (что отличается). Вы также не возитесь со своими массивами и не меняете порядок элементов. Вы также можете сравнить длину обоих массивов, если хотите, чтобы они были одинакового размера.

Это также самый быстрый способ сделать это (поправьте меня, если я ошибаюсь)

32 голосов
/ 01 февраля 2012

Сортировка массивов перед их сравнением - O (n log n). Более того, как отмечает Виктор, у вас возникнут проблемы, если массив содержит несортируемые объекты. Гистограммы быстрее сравнивать, O (n).

Вы найдете Enumerable # частота в Facets, но реализуйте ее самостоятельно, что довольно просто, если вы предпочитаете избегать добавления дополнительных зависимостей:

require 'facets'
[1, 2, 1].frequency == [2, 1, 1].frequency 
#=> true
18 голосов
/ 14 июня 2013

Если вы знаете, что ни в одном из массивов нет повторений (т. Е. Все элементы уникальны или вам все равно), использование множеств просто и доступно для чтения:

Set.new(array1) == Set.new(array2)
6 голосов
/ 01 февраля 2012

На самом деле этот метод #compare можно реализовать с помощью исправления обезьяны класса Array следующим образом:

class Array
  def compare(other)
    sort == other.sort
  end
end

Имейте в виду, что исправление обезьяны редко считается хорошей практикой, и выследует осторожно использовать его.

Возможно, есть лучший способ сделать это, но это то, что пришло на ум.Надеюсь, это поможет!

3 голосов
/ 07 декабря 2015

Вы можете открыть 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
3 голосов
/ 20 марта 2015

Самый элегантный способ, который я нашел:

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
0 голосов
/ 07 июня 2014

Вот версия, которая будет работать с несортируемыми массивами

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...