Eliminar elementos duplicados de la matriz en Ruby


325

Tengo una matriz Ruby que contiene elementos duplicados.

array = [1,2,2,1,4,4,5,6,7,8,5,6]

¿Cómo puedo eliminar todos los elementos duplicados de esta matriz y al mismo tiempo conservar todos los elementos únicos sin usar for-loops e iteraciones?

Respuestas:


722
array = array.uniq

uniq elimina todos los elementos duplicados y retiene todos los elementos únicos en la matriz.

Esta es una de las muchas bellezas del lenguaje Ruby.


50
no, el uniq! El método devolverá nil si la matriz ha sido única aún. Ej: a = [1,2,3,4] a.uniq -> [1,2,3,4] pero a.uniq! -> nil
duykhoa

15
realmente no vería esto como una belleza del lenguaje ruby ​​... ¿es solo la belleza de la biblioteca estándar ruby? no me malinterpreten, hay muchas cosas hermosas sobre el idioma.
Justin L.

77
escribe lo mismo en Objective-C, Javascript y PHP. ¡Entonces dinos que Ruby no es un lenguaje hermoso!
Adam Waite

3
Esto también funciona para tipos complejos: [{how: "are"}, {u:"doing"}, {how: "are"}].uniq => [{:how=>"are"}, {:u=>"doing"}]
Blaskovicz

55
sobre lo que dice @duykhoa, el uniq! devuelve el método nulo, pero por lo general no se preocupan por el regreso de un .uniq!que hace el trabajo sobre el objeto en sí mismo
carpinchosaurio

82

Puedes devolver la intersección.

a = [1,1,2,3]
a & a

Esto también eliminará duplicados.


12
Funcionalmente, esta respuesta es correcta, pero creo que esto es notablemente menos legible que solo usar uniq.
Fiona T

21
Solo lo estaba poniendo aquí para que quien visite esta página vea otras formas de hacerlo también, no estaba tratando de decir que es mejor de ninguna manera.
jaredsmith

3
La razón por la que esto funciona es porque cuando se usan operaciones de conjunto, la matriz resultante se trata como un conjunto, que es una estructura de datos que generalmente no tiene valores repetidos. Usar a | a(union) haría el mismo truco.
Cezar

47

Puede eliminar los elementos duplicados con el método uniq:

array.uniq  # => [1, 2, 4, 5, 6, 7, 8]

Lo que también podría ser útil saber es que uniqtoma un bloque, por lo que si tiene un conjunto de claves:

["bucket1:file1", "bucket2:file1", "bucket3:file2", "bucket4:file2"]

y desea saber cuáles son los archivos únicos, puede averiguarlo con:

a.uniq { |f| f[/\d+$/] }.map { |p| p.split(':').last }

55
Estoy un poco confundido por esto. El bloque se usa si necesita su propia función de comparación; en su ejemplo, enviar uniqa esa matriz sin un bloque devolvería el mismo valor que con su bloque.
hdgarrood

18

Solo otra alternativa si a alguien le importa.

También puede usar el to_setmétodo de una matriz que convierte la matriz en un conjunto y, por definición, los elementos del conjunto son únicos.

[1,2,3,4,5,5,5,6].to_set => [1,2,3,4,5,6]

44
Si le importa la memoria, to_setasignará 4 objetos, mientras que uniqasigna uno.
Jan Klimo

18

Si alguien buscaba una forma de eliminar todas las instancias de valores repetidos, consulte " ¿Cómo puedo extraer elementos repetidos de manera eficiente en una matriz Ruby? ".

a = [1, 2, 2, 3]
counts = Hash.new(0)
a.each { |v| counts[v] += 1 }
p counts.select { |v, count| count == 1 }.keys # [1, 3]

3
O simplemente podría hacerlo a = [1, 2, 2, 3] a.find_all { |x| a.count(x) == 1 } # [1, 3]
Tim Wright

La pregunta vinculada no es la misma; Se pregunta cómo encontrar valores duplicados y devolverlos. El OP quiere eliminar duplicados.
El hombre de hojalata

0

Solo para proporcionar una idea:

require 'fruity'
require 'set'

array = [1,2,2,1,4,4,5,6,7,8,5,6] * 1_000

def mithun_sasidharan(ary)
  ary.uniq
end

def jaredsmith(ary)
  ary & ary
end

def lri(ary)
  counts = Hash.new(0)
  ary.each { |v| counts[v] += 1 }
  counts.select { |v, count| count == 1 }.keys 
end

def finks(ary)
  ary.to_set
end

def santosh_mohanty(ary)
    result = ary.reject.with_index do |ele,index|
      res = (ary[index+1] ^ ele)
      res == 0
    end
end

SHORT_ARRAY = [1,1,2,2,3,1]
mithun_sasidharan(SHORT_ARRAY) # => [1, 2, 3]
jaredsmith(SHORT_ARRAY) # => [1, 2, 3]
lri(SHORT_ARRAY) # => [3]
finks(SHORT_ARRAY) # => #<Set: {1, 2, 3}>
santosh_mohanty(SHORT_ARRAY) # => [1, 2, 3, 1]

puts 'Ruby v%s' % RUBY_VERSION

compare do
  _mithun_sasidharan { mithun_sasidharan(array) }
  _jaredsmith { jaredsmith(array) }
  _lri { lri(array) }
  _finks { finks(array) }
  _santosh_mohanty { santosh_mohanty(array) }
end

Lo cual, cuando se ejecuta, da como resultado:

# >> Ruby v2.7.1
# >> Running each test 16 times. Test will take about 2 seconds.
# >> _mithun_sasidharan is faster than _jaredsmith by 2x ± 0.1
# >> _jaredsmith is faster than _santosh_mohanty by 4x ± 0.1 (results differ: [1, 2, 4, 5, 6, 7, 8] vs [1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, ...
# >> _santosh_mohanty is similar to _lri (results differ: [1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, 7, 8, 5, 6, 1, 2, 1, 4, 5, 6, ...
# >> _lri is similar to _finks (results differ: [] vs #<Set: {1, 2, 4, 5, 6, 7, 8}>)

Nota: estos arrojaron malos resultados:

  • lri(SHORT_ARRAY) # => [3]
  • finks(SHORT_ARRAY) # => #<Set: {1, 2, 3}>
  • santosh_mohanty(SHORT_ARRAY) # => [1, 2, 3, 1]

-4

Intente usar el operador XOR, sin usar las funciones integradas:

a = [3,2,3,2,3,5,6,7].sort!

result = a.reject.with_index do |ele,index|
  res = (a[index+1] ^ ele)
  res == 0
end

print result

Con funciones integradas:

a = [3,2,3,2,3,5,6,7]

a.uniq

2
No he votado negativamente y no sé casi nada sobre Ruby, pero ¿no es .sort!también una función incorporada?
Carolus
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.