Restar una matriz de otra en Ruby


82

Tengo dos matrices de tareas: creadas y asignadas. Quiero eliminar todas las tareas asignadas de la matriz de tareas creadas. Aquí está mi código funcional, pero desordenado:

    @assigned_tasks = @user.assigned_tasks
    @created_tasks = @user.created_tasks

    #Do not show created tasks assigned to self
    @created_not_doing_tasks = Array.new
    @created_tasks.each do |task|
        unless @assigned_tasks.include?(task)
            @created_not_doing_tasks << task
        end
    end

Estoy seguro de que hay una forma mejor. ¿Qué es? Gracias :-)


Apuesto a que bajo el capó la respuesta es hacer exactamente lo que ha codificado allí.
— baash05

Respuestas:


175

Puede restar matrices en Ruby:

[1,2,3,4,5] - [1,3,4]  #=> [2,5]

ary - other_ary → new_ary Array Diferencia

Devuelve una nueva matriz que es una copia de la matriz original, eliminando cualquier elemento que también aparezca en other_ary. El orden se conserva de la matriz original.

Compara elementos usando su hash y eql? métodos de eficiencia.

[ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ]

Si necesita un comportamiento similar a un conjunto, consulte la clase de biblioteca Conjunto.

Consulte la documentación de Array .


2
Arg. Gran momento en la palma de la mano para mí. Por alguna razón pensé que no funcionaría con objetos. Funcionó muy bien, ¡gracias!
— doctororange

28
cuidado con esto, primero pruébelo en IRB, por ejemplo: [5, 5, 5, 5] - [5, 5] = [] ... la resta elimina los elementos únicos en la matriz.
— hagope

9
También tenga en cuenta, esto no funcionará: [1,2]-[1,2,3] => []. Pero [1,2,3]-[1,2] => [3]. Argh.
— Zabba

17
Si piensa en términos de resta, entonces estos últimos "errores" tienen sentido. Para restar algo no está pidiendo una diferencia ... está pidiendo restar Y de X ... si Y tiene algo que ni siquiera está en X, entonces el resultado es algo 'indefinido', por lo tanto, el elemento Y adicional no sería no se incluirá en el resultado X.
— Bane

2
Específicamente, Array#-es una diferencia establecida. Es más una inversa de Array#|una unión de conjuntos que de una Array#+concatenación (¡no es una operación de conjuntos en absoluto!).
— ymbirtt

9

La solución anterior

a - b

elimina todas las instancias de elementos en la matriz bde la matriz a.

[ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ]  #=>  [ 3, 3, 5 ]

En algunos casos, desea que el resultado sea [1, 2, 3, 3, 5]. Es decir, no desea eliminar todos los duplicados, sino solo los elementos individualmente.

Podrías lograr esto por

class Array
  def delete_elements_in(ary)
    ary.each do |x|
      if index = index(x)
        delete_at(index)
      end
    end
  end
end

prueba

irb(main):198:0> a = [ 1, 1, 2, 2, 3, 3, 4, 5 ]
=> [1, 1, 2, 2, 3, 3, 4, 5]
irb(main):199:0> b = [ 1, 2, 4 ]
=> [1, 2, 4]
irb(main):200:0> a.delete_elements_in(b)
=> [1, 2, 4]
irb(main):201:0> a
=> [1, 2, 3, 3, 5]

El código funciona incluso cuando las dos matrices no están ordenadas. En el ejemplo, las matrices están ordenadas, pero esto no es necesario.


delete_elements_inno está disponible en Ruby propiamente dicho (ruby 2.6.3p62)
— qaisjp

@qaisjp, porque lo define el escritor. Tú también lo definirás. Mira el código sobre el código de prueba.
— ismailarilik

Aparentemente no puedo leer. Gracias, @ismailarilik.
— qaisjp
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.