Ruby Array.collect 迭代器块中的条件
Posted
技术标签:
【中文标题】Ruby Array.collect 迭代器块中的条件【英文标题】:Conditional in Ruby Array.collect Iterator Block 【发布时间】:2021-12-05 05:46:10 【问题描述】:任何人都可以阐明为什么会这样吗?我希望该集合省略 nil 结果,并且仅收集符合include?
条件的结果。第一个和第三个结果条目,我希望不会出现。出于某种原因,它们确实包括在内。我做错了什么?
f = [
"title"=>"Tuesday: Cloudy. High plus 12.",
"link"=>"type"=>"text/html",
"href"=>"https://www.weather.gc.ca/city/pages/mb-42_metric_e.html",
"title"=>"Tuesday night: Cloudy. High plus 2.",
"link"=>"type"=>"text/html",
"href"=>"https://www.weather.gc.ca/city/pages/mb-42_metric_e.html",
"title"=>"Wednesday: Cloudy. High plus 10.",
"link"=>"type"=>"text/html",
"href"=>"https://www.weather.gc.ca/city/pages/mb-42_metric_e.html",
"title"=>"Tuesday night: Cloudy. High plus 2.",
"link"=>"type"=>"text/html",
"href"=>"https://www.weather.gc.ca/city/pages/mb-42_metric_e.html"
]
conditions = f.collect |i| i['title'] if i['title'].include?('night')
==> [nil, "Tuesday night: Cloudy. High plus 2.", nil, "Tuesday night: Cloudy. High plus 2."]
【问题讨论】:
【参考方案1】:这是预期的行为 - map
将一个数组一对一地转换为任何形式的语句:
do_sth if some_condition
当某些条件不成立并且nil
只是一个对象时返回nil
。
处理此问题的标准方法是在调用 map 之前使用 select
或在 map
之后调用 compact
。
从 ruby 2.7 开始,我们有另一种方法将两者结合起来:filter_map 忽略返回的虚假值:
conditions = f.filter_map |i| i['title'] if i['title'].include?('night')
==> ["Tuesday night: Cloudy. High plus 2.", "Tuesday night: Cloudy. High plus 2."]
【讨论】:
可能是他们添加该方法的原因,因为人们正在应用条件并获得nils
。【参考方案2】:
因为在每次迭代中,collect/map 都会返回一些东西(在这种情况下也是 nil)...
您可以使用 select 来过滤您的数组。像这样的:
f.select |i| i['title'].include?('night') .collect |i| i['title']
【讨论】:
是的,我原以为 nils 不会出现。我想它展示了一个迭代。我现在选择了Array.compact
来删除nil
条目。【参考方案3】:
#map
将一个集合转换为另一个相同大小的集合。如果块返回 nil
值,那么这些 nil
s 将最终出现在新集合中。
如果标题不包含night,i['title'] if i['title'].include?('night')
之类的语句将返回 nil
。
您可以使用#filter_map
、#select
+ #map
、#inject
或 #each_with_object
我运行了一个快速的微基准测试并出人意料地迭代了两次集合(使用#select
AND #map
)并没有变慢。
items = [
"title"=>"Tuesday: Cloudy. High plus 12.",
"link"=>"type"=>"text/html",
"href"=>"https://www.weather.gc.ca/city/pages/mb-42_metric_e.html",
"title"=>"Tuesday night: Cloudy. High plus 2.",
"link"=>"type"=>"text/html",
"href"=>"https://www.weather.gc.ca/city/pages/mb-42_metric_e.html",
"title"=>"Wednesday: Cloudy. High plus 10.",
"link"=>"type"=>"text/html",
"href"=>"https://www.weather.gc.ca/city/pages/mb-42_metric_e.html",
"title"=>"Tuesday night: Cloudy. High plus 2.",
"link"=>"type"=>"text/html",
"href"=>"https://www.weather.gc.ca/city/pages/mb-42_metric_e.html"
]
require "benchmark/ips"
Benchmark.ips do |x|
x.compare!
x.report("filter_map") do
items.filter_map |item| item["title"] if item["title"].include?("night")
end
x.report("select_map") do
items.select |item| item["title"].include?("night") .map |item| item["title"]
end
x.report("each_with_object") do
items.each_with_object([]) |item, accu| accu << item["title"] if item["title"].include?("night"); nil
end
x.report("inject") do
items.inject([]) |accu, item| accu << item["title"] if item["title"].include?("night"); accu
end
end
【讨论】:
以上是关于Ruby Array.collect 迭代器块中的条件的主要内容,如果未能解决你的问题,请参考以下文章
C# 2.0 - 有没有办法用产生的迭代器块做一个`GroupBy`?