Пропустить итерацию в Enumerable # collect - PullRequest
54 голосов
/ 01 марта 2011
(1..4).collect do |x|
  next if x == 3
  x + 1
end # => [2, 3, nil, 5]
    # desired => [2, 3, 5]

Если условие для next выполнено, collect помещает nil в массив, тогда как я пытаюсь поместить элемент no в возвращаемый массив, еслиусловие выполнено.Возможно ли это без вызова delete_if { |x| x == nil } для возвращаемого массива?

(с использованием Ruby 1.8.7; мой фрагмент кода сильно абстрагирован)

Ответы [ 5 ]

78 голосов
/ 01 марта 2011

Существует метод Enumerable#reject, который служит только цели:

(1..4).reject{|x| x == 3}.collect{|x| x + 1}

Практика непосредственного использования вывода одного метода в качестве ввода другого называется цепочкой методов и очень распространена в Ruby.

КСТАТИ, map (или collect) используется для прямого отображения ввода, перечисляемого на выход. Если вам нужно вывести разное количество элементов, скорее всего, вам нужен другой метод Enumerable.

Редактировать: Если вас беспокоит тот факт, что некоторые элементы повторяются дважды, вы можете использовать менее элегантное решение на основе inject (или его аналогичный метод с именем each_with_object):

(1..4).each_with_object([]){|x,a| a << x + 1 unless x == 3}
46 голосов
/ 01 марта 2011

Я бы просто вызвал .compact в результирующем массиве, который удаляет все экземпляры nil в массиве. Если вы хотите изменить существующий массив (без причины), используйте .compact!:

(1..4).collect do |x|
  next if x == 3
  x
end.compact!
4 голосов
/ 01 марта 2011

просто предложение, почему бы вам не сделать это следующим образом:

result = []
(1..4).each do |x|
  next if x == 3
  result << x
end
result # => [1, 2, 4]

таким образом вы сохранили еще одну итерацию для удаления nil-элементов из массива.надеюсь, это поможет =)

0 голосов
/ 15 июня 2014

Вы можете включить принятие решения во вспомогательный метод и использовать его через Enumerable#reduce:

def potentially_keep(list, i)
  if i === 3
    list
  else
    list.push i
  end
end
# => :potentially_keep

(1..4).reduce([]) { |memo, i| potentially_keep(memo, i) }
# => [1, 2, 4]
0 голосов
/ 01 марта 2011

я бы предложил использовать:

(1..4).to_a.delete_if {|x| x == 3}

вместо оператора collect + next.

...