Search code examples
rubyenumerable

Skip over iteration in Enumerable#collect


(1..4).collect do |x|
  next if x == 3
  x + 1
end # => [2, 3, nil, 5]
    # desired => [2, 3, 5]

If the condition for next is met, collect puts nil in the array, whereas what I'm trying to do is put no element in the returned array if the condition is met. Is this possible without calling delete_if { |x| x == nil } on the returned array?

My code excerpt is heavily abstracted, so looking for a general solution to the problem.


Solution

  • In Ruby 2.7+, it’s possible to use filter_map for this exact purpose. From the docs:

    Returns an array containing truthy elements returned by the block.

    (0..9).filter_map {|i| i * 2 if i.even? }   #=> [0, 4, 8, 12, 16]
    {foo: 0, bar: 1, baz: 2}.filter_map {|key, value| key if value.even? }  #=> [:foo, :baz]
    

    For the example in the question: (1..4).filter_map { |x| x + 1 unless x == 3 }.

    See this post for comparison with alternative methods, including benchmarks.