Віднімання одного масиву з іншого в Ruby


83

У мене є два масиви Завдань - створені та призначені. Я хочу видалити всі призначені завдання з масиву створених завдань. Ось мій робочий, але безладний код:

    @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

Я впевнений, що є кращий спосіб. Що це? Дякую :-)


Б'юся об заклад, під капотом відповідь робить саме те, що ви там закодували.
baash05,

Відповіді:


177

Ви можете відняти масиви в Ruby:

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

ary - other_ary → new_ary Різниця масиву

Повертає новий масив, який є копією вихідного масиву, видаляючи всі елементи, які також з'являються в other_ary. Порядок збережений з оригінального масиву.

Він порівнює елементи, використовуючи їх хеш і eql? методи ефективності.

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

Якщо вам потрібна поведінка, схожа на набір, див. Бібліотечний клас Set.

Див. Документацію до масиву .


2
Арг. Велика особа-долоня для мене. Чомусь я думав, що це не спрацює з об’єктами. Працювали просто чудово - спасибі!
доктороранж

28
обережно з цим, спершу протестуйте його в IRB, наприклад: [5, 5, 5, 5] - [5, 5] = [] ... віднімання видаляє унікальні елементи з масиву.
hagope

9
Також зверніть увагу, що це не буде працювати: [1,2]-[1,2,3] => []. Але [1,2,3]-[1,2] => [3]. Арг.
Zabba

17
Якщо ви думаєте з точки зору віднімання, то це останнє "дістати" насправді має сенс. Щоб відняти щось, про що ви не вимагаєте різниці ... ви просите відняти Y від X ... якщо Y має щось навіть не в X, то результат виглядає як би "невизначений", отже, зайвий Y-елемент не буде не буде включено в X-результат.
Бейн

2
Зокрема, Array#-це встановлена ​​різниця. Це скоріше обернене Array#|, об'єднання множин, ніж Array#+конкатенація (зовсім не операція набору!).
ymbirtt 02.03.15

9

Вищевказане рішення

a - b

видаляє всі екземпляри елементів масиву bз масиву a.

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

У деяких випадках ви хочете, щоб результат був [1, 2, 3, 3, 5]. Тобто ви не хочете видаляти всі дублікати, а лише елементи окремо.

Ви можете досягти цього шляхом

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

тест

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]

Код працює навіть тоді, коли два масиви не відсортовані. У цьому прикладі масиви сортуються, але це не потрібно.


delete_elements_inнедоступний у власне Ruby (ruby 2.6.3p62)
qaisjp

@qaisjp, бо це визначено автором. Ви також визначите це. Подивіться на код над тестовим кодом.
ismailarilik
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.