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 值,那么这些 nils 将最终出现在新集合中。

如果标题不包含nighti['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#中yield用法

C# 2.0 - 有没有办法用产生的迭代器块做一个`GroupBy`?

yield return关键字怎么使用?

C#中的yield return与Unity中的Coroutine(协程)

有人可以解释 Ruby 在块中使用管道字符吗?

C#基础之yield与Singleton