Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

205
Views
Conditional in Ruby Array.collect Iterator Block

Can anybody shine some light on why this is behaving like this? I'm expecting the collection to omit nil results, and only collect those that qualify under the condition of the include?. First and third result entries, I expect to not be there. For some reason, they are indeed included. What am I doing wrong?

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."]
over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

This is expected behaviour - map transforms an array one to one and any statement in form:

do_sth if some_condition

returns nil when some condition is falsey and nil is just an object as anything else.

Standard way of dealing with this would be either to use select before call to map or to call compact after map.

Since ruby 2.7 we have another method combining the two: filter_map which ignores returned falsy values:

conditions = f.filter_map { |i| i['title'] if i['title'].include?('night') }
==> ["Tuesday night: Cloudy. High plus 2.", "Tuesday night: Cloudy. High plus 2."]
over 4 years ago · Santiago Trujillo Report

0

Because in every Iteration, collect/map returns something (also nil in this case)...

You could use select to filter your array. Something like this:

f.select { |i| i['title'].include?('night') }.collect {|i| i['title']}
over 4 years ago · Santiago Trujillo Report

0

#map transforms one collection to another collection of the same size. If the block returns nil values, then those nils will end up in the new collection.

A statement like i['title'] if i['title'].include?('night') will return nil in the case that the title does not contain night.

You can either use #filter_map, #select + #map, #inject or #each_with_object

I ran a quick micro-benchmark and suprisingly iterating the collection twice (using #select AND #map) is not slower.

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
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!