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

如果满足条件,nextcollect放入nil数组中,而我要做的是,如果满足条件,则不将任何元素放入返回的数组中。delete_if { |x| x == nil }如果不调用返回的数组,这可能吗?

(使用 Ruby 1.8.7;我的代码摘录非常抽象)

4

6 回答 6

78

有一种方法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}
于 2011-03-01T09:11:45.470 回答
49

我会简单地调用.compact结果数组,它会删除数组中任何 nil 实例。如果您希望它修改现有数组(没有理由不这样做),请使用.compact!

(1..4).collect do |x|
  next if x == 3
  x
end.compact!
于 2011-03-01T08:42:46.173 回答
8

红宝石 2.7+

现在有!

Ruby 2.7 正是filter_map为此目的而引入的。它是惯用的和高性能的,我希望它很快就会成为常态。

例如:

numbers = [1, 2, 5, 8, 10, 13]
numbers.filter_map { |i| i * 2 if i.even? }
# => [4, 16, 20]

这是一个很好的阅读主题

希望这对某人有用!

于 2019-08-02T09:35:07.900 回答
4

只是一个建议,你为什么不这样做:

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

这样,您保存了另一个迭代以从数组中删除 nil 元素。希望它有帮助 =)

于 2011-03-01T08:58:35.307 回答
0

我建议使用:

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

而不是 collect + next 语句。

于 2011-03-01T08:48:00.227 回答
0

您可以将决策拉入辅助方法,并通过以下方式使用它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]
于 2014-06-15T05:52:15.213 回答