Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

211
Visualizações
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 Respostas
Responde à pergunta

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 Relatório

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda