Estou usando Ruby 1.8.6 com Rails 1.2.3 e preciso determinar se dois arrays têm os mesmos elementos, independentemente de estarem ou não na mesma ordem. Um dos arrays tem garantia de não conter duplicatas (o outro pode, caso em que a resposta é não).
Meu primeiro pensamento foi
require 'set'
a.to_set == b.to_set
mas eu queria saber se havia uma maneira mais eficiente ou idiomática de fazer isso.
ruby
arrays
comparison
Taymon
fonte
fonte
[1,2]
e[2,1,1]
têm os mesmos elementos?)difference
que oferece uma solução muito rápida e muito legível. Mais informações aqui.Respostas:
Isso não requer conversão para definir:
fonte
.uniq.sort
então? Alémuniq
é semelhante ato_set
internamente mais adicional.to_a.sort
uniq
s. Na verdade acabei criando um dos arrays comRange#to_a
, então só tive que fazersort
o outro.para duas matrizes A e B: A e B têm o mesmo conteúdo se:
(A-B).blank? and (B-A).blank?
ou você pode apenas verificar:
((A-B) + (B-A)).blank?
Também como sugerido por @ cort3z, esta solução também funciona para matrizes polimórficas, ou seja
::::::::::: EDITAR ::::::::::::::
Como sugerido nos comentários, a solução acima falha para duplicatas. Embora de acordo com a pergunta que nem mesmo seja necessária, uma vez que o solicitante não está interessado em duplicatas (ele está convertendo suas matrizes para definir antes de verificar e isso mascara as duplicatas e mesmo se você olhar para a resposta aceita, ele está usando um operador .uniq antes de verificar e isso também mascara as duplicatas). Mesmo assim, se você tiver interesse em duplicatas, basta adicionar uma verificação de contagem para corrigir o mesmo (de acordo com a pergunta, apenas um array pode conter duplicatas). Portanto, a solução final será:
A.size == B.size and ((A-B) + (B-A)).blank?
fonte
A=[1]
eB=[1,1]
, ambos(A-B)
e(B-A)
retornarão em branco. Consulte a documentação do Array .a.to_set == b.to_set
e a resposta aceita está usandoa.uniq.sort == b.uniq.sort
e ambos fornecem exatamente o mesmo resultado que((A-B) + (B-A)).blank?
A = [1] e B = [1,1] concorda? Como ele estava apenas pedindo uma melhoria em relação à solução original, minha solução original ainda funciona :). aceita?A = [123, "test", [], some_object, nil]
eB = A#because I am lazy
, em seguida,A.uniq.sort
irá lançar um erro (a comparação de string e Array falhou).A = [1, 1, 2]
eB = [1, 2, 2]
Comparsões de velocidade
fonte
sort
a velocidade deto_set
começar a ter um desempenho superior com matrizes grandes o suficiente, onde O (n logn) começaria a importar mais do que o esforço necessário para converter a matriz em conjuntoRuby 2.6+
Ruby foi introduzido
difference
em 2.6.Isso fornece uma solução muito rápida e legível aqui, da seguinte maneira:
Executando os benchmarks:
Espero que ajude alguém!
fonte
Quando os elementos de
a
eb
sãoComparable
,Correção da resposta de @mori com base no comentário de @steenslag
fonte
a
eb
pode ser classificado.Se você espera
[:a, :b] != [:a, :a, :b]
to_set
não funciona. Em vez disso, você pode usar a frequência:fonte
a.sort == b.sort
se ele se preocupa com a frequência?["", :b].frequency == [:b, ""].frequency #=> true
a.group_by{|i| i} == b.group_by{|i| i}
Se você souber que as matrizes têm o mesmo comprimento e nenhuma delas contém duplicatas, isso também funciona:
Explicação: o
&
operador, neste caso, retorna uma cópia de a1 sem quaisquer itens não encontrados em a2, que é o mesmo que o a1 original se ambas as matrizes tiverem o mesmo conteúdo sem duplicatas.Análise: considerando que a ordem não foi alterada, estou supondo que isso seja implementado como uma iteração dupla de forma consistente
O(n*n)
, notavelmente pior para grandes arrays doa1.sort == a2.sort
que aquela que deveria funcionar com o pior casoO(n*logn)
.fonte
a1 = [1,2,3], a2 = [2, 1, 3]
a1 && a2
retorna[2,1,3]
para mim que não é igual aa1
a1==a2
? Pode funcionar searray1
do lado direito da igualdade for substituído porarray2
, mas duvido que a ordem dos elementos retornados por&
seja garantida.&
é um operador de interseção de conjuntos para matrizes,&&
é lógico AND - eles são muito diferentes!Uma abordagem é iterar sobre a matriz sem duplicatas
Isso retorna uma série de verdades. Se algum falso aparecer, o externo
include?
retornará verdadeiro. Portanto, você tem que inverter tudo para determinar se é uma correspondência.fonte
combinando
&
esize
pode ser rápido também.fonte