Подтвердить что ты не робот

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

4b9b3361

Ответ 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

Извините за мой плохой английский!