Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

202
Vistas
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 Respuestas
Responde la pregunta

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 Denunciar

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 Denunciar

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 Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda