PREVENT nil values while enumerating in Ruby

2250 views ruby
-1

Removing nils is quite simple, however, I'd like to know:

1) What am I doing wrong, why does my array result below include nils?

2) How I can PREVENT the nils from being added to my array, instead of removing them after the fact.

@cars = Array.new
plucked_array = [
    [8, "Chevy", "Camaro", 1],
    [10, "Ford", "Mustang", 1],
    [10, "Dodge", "Challenger", 2]
]
plucked_array.
    map { |id, make, model, model_count|
      @cars[id] ||= {name: make, id: make, data: []}
      @cars[id][:data].push([model, model_count])
    }
puts @cars.inspect 
#=>[nil, nil, nil, nil, nil, nil, nil, nil, {"name"=>"Chevy", "id"=>"Chevy", "data"=>[["Camaro", 1]]}, nil, {"name"=>"Dodge", "id"=>"Dodge", "data"=>[["Mustang", 1], ["Challenger", 2]]}]

I also attempted @theTinMan's recommendation to select first, but I had the same results:

plucked_array.select { |id, make, model, model_count|
  @cars[id] = {'name' => make, 'id' => make, 'data' => []}
}.map { |id, make, model, model_count|
  @cars[id]['data'].push([model, model_count])
}
puts @cars.inspect
#=>[nil, nil, nil, nil, nil, nil, nil, nil, {"name"=>"Chevy", "id"=>"Chevy", "data"=>[["Camaro", 1]]}, nil, {"name"=>"Dodge", "id"=>"Dodge", "data"=>[["Mustang", 1], ["Challenger", 2]]}]

answered question

2 Answers

12

I would go for more of a reduce approach because you are taking a list and boiling it down into another object. each_with_object does the reduce but implicitly returns the obj (in this case cars) in every loop

new_list = plucked_array.each_with_object({}) do |(id, make, model, model_count), cars|
  cars[id] ||= {name: make, id: make, data: []}
  cars[id][:data].push([model, model_count])
end

Side note: map is normally more for transforms or equivalent changes, which is i think why it feels off here.

posted this
12

I can suggest grouping by id before. It's not clear to me why Dodge and Ford (which is Fiat Chrysler Automobiles) are both under Ford (missing Dodge). So, maybe with this I'm giving an undesired output, maybe not. In case I'll make an edit or remove the answer.

Anyway:

plucked_array.group_by(&:first).transform_values{ |v| v.map{ |id, make, model, model_count|  {name: make, id: make, data: [model, model_count]} }}

#  {
#    8=>[{:name=>"Chevy", :id=>"Chevy", :data=>["Camaro", 1]}],
#    10=>[{:name=>"Ford", :id=>"Ford", :data=>["Mustang", 1]}, {:name=>"Dodge", :id=>"Dodge", :data=>["Challenger", 2]}]
#  }

posted this

Have an answer?

JD

Please login first before posting an answer.