当前位置: 首页 > 知识库问答 >
问题:

如何在Ruby中映射和删除nil值

山阳辉
2023-03-14

我有一个<code>map</code>,它要么更改值,要么将其设置为nil。然后我想从列表中删除nil条目。该列表不需要保存。

这是我目前拥有的:

# A simple example function, which returns a value or nil
def transform(n)
  rand > 0.5 ? n * 10 : nil }
end

items.map! { |x| transform(x) } # [1, 2, 3, 4, 5] => [10, nil, 30, 40, nil]
items.reject! { |x| x.nil? } # [10, nil, 30, 40, nil] => [10, 30, 40]

我知道我可以做一个循环,并有条件地在另一个数组中收集,如下所示:

new_items = []
items.each do |x|
    x = transform(x)
    new_items.append(x) unless x.nil?
end
items = new_items

但这似乎不是那么惯用。有没有一种很好的方法可以在列表上映射函数,随时删除/排除 nils?

共有3个答案

阎承
2023-03-14

红宝石 2.7

现在有了!

Ruby 2.7正是为了这个目的引入了< code>filter_map。它是习惯性的和表演性的,我希望它很快成为规范。

例如:

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

在这种情况下,当块求值为false时,只需:

items.filter_map { |x| process_x url }

“Ruby 2.7添加了Enumerable#filter_map”是一篇很好的文章,针对解决这个问题的一些早期方法提供了一些性能基准:

N = 100_000
enum = 1.upto(1_000)
Benchmark.bmbm do |x|
  x.report("select + map")  { N.times { enum.select { |i| i.even? }.map{ |i| i + 1 } } }
  x.report("map + compact") { N.times { enum.map { |i| i + 1 if i.even? }.compact } }
  x.report("filter_map")    { N.times { enum.filter_map { |i| i + 1 if i.even? } } }
end

# Rehearsal -------------------------------------------------
# select + map    8.569651   0.051319   8.620970 (  8.632449)
# map + compact   7.392666   0.133964   7.526630 (  7.538013)
# filter_map      6.923772   0.022314   6.946086 (  6.956135)
# --------------------------------------- total: 23.093686sec
# 
#                     user     system      total        real
# select + map    8.550637   0.033190   8.583827 (  8.597627)
# map + compact   7.263667   0.131180   7.394847 (  7.405570)
# filter_map      6.761388   0.018223   6.779611 (  6.790559)
邵亦
2023-03-14

尝试使用减少注入

[1, 2, 3].reduce([]) { |memo, i|
  if i % 2 == 0
    memo << i
  end

  memo
}

我同意大家公认的答案,我们不应该< code>map和< code>compact,但原因不一样。

我觉得在那个地图的深处,那么紧凑相当于选择然后地图。考虑一下:地图是一个一对一的功能。如果要从一组值进行映射,并且进行了映射,则需要在输出集中为输入集中的每个值提供一个值。如果您必须事先选择,那么您可能不希望在片场使用地图。如果你必须在之后选择(或压缩),那么你可能不希望在片场有地图。无论哪种情况,您都会在整个集合上迭代两次,而归约只需要一次。

此外,在英语中,您正在尝试“将一组整数减少为一组偶数整数”。

汝岳
2023-03-14

您可以使用< code>compact:

[1, nil, 3, nil, nil].compact
=> [1, 3] 

我想提醒大家,如果您得到一个数组,其中包含nils作为<code>map</code>块的输出,并且该块试图有条件地返回值,那么您就有代码气味,需要重新思考您的逻辑。

例如,如果你正在做这样的事情:

[1,2,3].map{ |i|
  if i % 2 == 0
    i
  end
}
# => [nil, 2, nil]

那就不要。相反,在< code >映射之前,< code >拒绝您不想要的东西或< code >选择您想要的东西:

[1,2,3].select{ |i| i % 2 == 0 }.map{ |i|
  i
}
# => [2]

我考虑使用<code>compact</code>来清理一个烂摊子,这是为了摆脱我们没有正确处理的事情,通常是因为我们不知道会发生什么。我们应该始终知道在我们的程序中丢弃了什么样的数据;意外/未知数据不正确。每当我在研究的数组中看到nil时,我都会深入研究它们存在的原因,看看是否可以改进生成数组的代码,而不是让Ruby浪费时间和内存生成nil,然后在数组中筛选以稍后删除它们。

'Just my $%0.2f.' % [2.to_f/100]
 类似资料:
  • 只有当每个键在map1中都有唯一的值时,我才会陷入如何将键值对从map1转移到map2的困境。 假设我有以下地图: 地图1:[1,2][2,4][4,4] 我想算法应该是: 遍历第一张地图中的条目。 向map2添加密钥。 将一个值添加到检查map2的值的集合 如果值是重复的,则不会将该值添加到集合中,并且忽略将其相应的键添加到map2。 代码片段: 我的想法是如何在正确的轨道上完成的吗?这里迷失了

  • 我在团队项目中的tfs中有一个项目,然后我们将该项目移动到另一个团队项目中不同的位置。 我已将Jenkins配置为连接到团队项目并生成我的解决方案,但当我更改设置以连接到新的tfs团队项目时,它显示以下错误: 所以上面显示有一个现有的工作区,所以我运行下面的命令来删除它 它提示工作区已被删除,但我仍然收到同样的错误。 我还通过运行以下命令检查了映射是否已被删除: 但它表示工作空间并不像预期的那样存

  • 问题内容: 我有一条路线映射为: 如何在运行时删除/重新映射此路由到空处理程序? 问题答案: 这将删除中间件和/或(获取/发布)路由。在express@4.9.5上测试 请注意,它 要求 中间件/路由功能具有 名称 : 如果该函数是匿名的, 它将不起作用 :

  • 自从我将我的项目从jhipster 5.8.2升级到jhipster 6.5.1以来,我对Mapper有很多警告。 我会正确处理此警告,不会在所有映射器中添加此属性: 例如,我有以下错误: 在我的对象权限中,我有: 以及以下许可: 和映射器: 带有“忽略=true”的ligne不起作用。 你有什么想法吗?

  • 我这里有一个奇怪的问题,如果我错了,请原谅我。 我这里的问题是,我在应用程序中为两个实体定义了一个manytone映射。删除时,我想忽略删除其他实体。 假设Emp到Dept有多个关系,我正在通过会话删除Emp记录。删除(EmpId),此时我不想删除与Emp实体关联的部门。 我不能在hbm中改变级联选项。 这种情况类似于 “如果有10个emp属于部门编号101,并且在删除任何一个emp时,它也将尝试

  • 如何在不删除索引映射的情况下从elasticsearch数据库中删除数据? 我是Tire gem,使用删除命令删除我所有的映射并再次运行创建命令。我想避免创建命令一次又一次地运行。 请帮我解决这个问题。