Вычитание одного массива из другого в Ruby

У меня есть два массива задач - созданные и назначенные. Я хочу удалить все назначенные задачи из массива созданных задач. Вот мой рабочий, но грязный код:

    @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

Я уверен, что есть лучший способ. Что это такое? Спасибо :-)


person doctororange    schedule 28.07.2009    source источник
comment
Бьюсь об заклад, под капотом ответ делает именно то, что вы там закодировали.   -  person baash05    schedule 16.05.2012


Ответы (2)


Вы можете вычитать массивы в 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.

См. документацию по Array.

person hobodave    schedule 28.07.2009
comment
Арг. Большой момент для меня. Я почему-то думал, что с объектами это не сработает. Сработало просто отлично - спасибо! - person doctororange; 28.07.2009
comment
будьте осторожны с этим, сначала проверьте его в IRB, например: [5, 5, 5, 5] - [5, 5] = [] ... вычитание удаляет уникальные элементы в массиве. - person hagope; 10.08.2011
comment
@hagope, да, он жадный. - person poige; 31.05.2012
comment
Также обратите внимание, что это не сработает: [1,2]-[1,2,3] => []. Но [1,2,3]-[1,2] => [3]. Арх. - person Zabba; 28.06.2012
comment
Если вы думаете с точки зрения вычитания, то эти последние уловки действительно имеют смысл. Чтобы вычесть что-то, что вы не запрашиваете diff... вы просите вычесть Y из X... если Y имеет что-то даже не в X, тогда результат является своего рода «неопределенным», поэтому дополнительный элемент Y не будет включен в X-результат. - person Bane; 04.10.2013
comment
В частности, Array#- — это разность наборов. Это скорее инверсия Array#|, объединения множества, чем Array#+, конкатенация (совсем не операция множества!). - person ymbirtt; 02.03.2015
comment
Если вы думаете с точки зрения вычитания, то если я начну с 3 монет, помеченных 2 ([2,2,2]), и вычту одну монету, помеченную 2 ([2]), я закончу с 2 монетами, помеченными 2 ([ 2,2]). Так что да, он ведет себя больше как набор. - person Trejkaz; 02.08.2017
comment
чтобы получить перекресток [1,2,3,5] & [1,3,4] => [1, 3] - person Lex; 03.08.2017

Приведенное выше решение

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]

Код работает, даже если два массива не отсортированы. В примере массивы отсортированы, но это не обязательно.

person Zack Xu    schedule 15.09.2017
comment
delete_elements_in недоступен в самом Ruby (ruby 2.6.3p62) - person qaisjp; 12.10.2020
comment
@qaisjp, потому что это определено писателем. Вы должны определить это, слишком. Посмотрите на код над тестовым кодом. - person ismailarilik; 19.10.2020