Odejmowanie jednej tablicy od drugiej w Rubim

83

Mam dwie tablice zadań - utworzone i przypisane. Chcę usunąć wszystkie przydzielone zadania z tablicy utworzonych zadań. Oto mój działający, ale niechlujny kod:

    @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

Jestem pewien, że jest lepszy sposób. Co to jest? Dzięki :-)

Doctororange
źródło
Założę się, że odpowiedź brzmi: robi to, co tam zakodowałeś.
baash05

Odpowiedzi:

177

W Rubim możesz odejmować tablice:

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

ary - inny_ary → nowy_ary Różnica w tablicy

Zwraca nową tablicę, która jest kopią oryginalnej tablicy, usuwając wszystkie elementy, które pojawiają się również w other_ary. Kolejność jest zachowywana z oryginalnej tablicy.

Porównuje elementy za pomocą ich skrótu i ​​eql? metody zwiększania wydajności.

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

Jeśli potrzebujesz zachowania podobnego do zestawu, zobacz zestaw klas biblioteki.

Zobacz dokumentację Array .

hobodave
źródło
2
Arg. Wielka chwila dla mnie. Z jakiegoś powodu pomyślałem, że to nie zadziała z przedmiotami. Działało dobrze - dzięki!
doctororange
28
ostrożnie z tym, najpierw przetestuj go w IRB, na przykład: [5, 5, 5, 5] - [5, 5] = [] ... odejmowanie usuwa unikalne elementy z tablicy.
hagope
9
Należy również pamiętać, to nie będzie działać: [1,2]-[1,2,3] => []. Ale [1,2,3]-[1,2] => [3]. Argh.
Zabba
17
Jeśli myślisz w kategoriach odejmowania, to te ostatnie „pułapki” faktycznie mają sens. Aby odjąć coś, o co nie prosisz o różnicę ... prosisz o odjęcie Y od X ... jeśli Y ma coś, czego nie ma nawet w X, wynik jest w pewnym sensie „niezdefiniowany”, stąd dodatkowy element Y nie nie zostaną uwzględnione w wyniku X.
Bane
2
W szczególności Array#-jest to ustalona różnica. Jest to bardziej odwrotność Array#|set union niż Array#+konkatenacji (wcale nie jest to operacja na zbiorach!).
ymbirtt
9

Powyższe rozwiązanie

a - b

usuwa wszystkie wystąpienia elementów w tablicy bz tablicy a.

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

W niektórych przypadkach chcesz, aby wynik był [1, 2, 3, 3, 5]. Oznacza to, że nie chcesz usuwać wszystkich duplikatów, ale tylko poszczególne elementy.

Możesz to osiągnąć przez

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

test

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]

Kod działa nawet wtedy, gdy dwie tablice nie są posortowane. W tym przykładzie tablice są sortowane, ale nie jest to wymagane.

Zack Xu
źródło
delete_elements_innie jest dostępny we właściwym Rubim (ruby 2.6.3p62)
qaisjp
@qaisjp, ponieważ jest zdefiniowany przez autora. Ty też to zdefiniujesz. Spójrz na kod nad kodem testowym.
ismailarilik