0

I have this loop:

car_data = Hash.new
Car.all.each do |c|
  car_data[c.brand] = c.id
  car_data['NEW'] << c.id if c.new == 1
end

I have this snipper and trying to save all the new cars to car_data['NEW'], but this code keeps only one item in the hash (there should be 8).

I also tried to define that car_data['NEW'] as an array:

car_data = Hash.new
car_data['NEW'] = Hash.new
Car.all.each do |c|
  car_data[c.brand] = c.id
  car_data['NEW'] << c.id if c.new == 1
end

But the result was the same - just one item. How do I save the whole array to the hash key element?

Thank you.

1
  • 1
    Ruby convention is to use { } for a new Hash, that calling Hash.new is only necessary when supplying defaults like Hash.new(0). Less is more. Commented Jul 27, 2016 at 17:08

3 Answers 3

3

car_data['NEW'] has to be declared as Array.

car_data = Hash.new
car_data['NEW'] = []
Car.all.each do |c|
  car_data[c.brand] = c.id
  car_data['NEW'] << c.id if c.new == 1
end

You can also do it in a single step

car_data = { new: [] }
Car.all.each do |c|
  car_data[c.brand] = c.id
  car_data[:new] << c.id if c.new == 1
end

Frankly, it seems a little bit odd to me to use a Hash in that way. In particular, mixin different kind of information in Hash is a very bad approach inherited from other non object oriented languages.

I'd use at least two separate variables. But I don't know enough about the context to provide a meaningful example.

Sign up to request clarification or add additional context in comments.

Comments

3

You wrote, that you tried to define (initialize) car_data['NEW'] as an array, but what you did is... initialized it as a hash.

Change:

car_data['NEW'] = Hash.new

To:

car_data['NEW'] = []

The full code would look like:

car_data = Hash.new
car_data['NEW'] = []
Car.all.each do |c|
  car_data[c.brand] = c.id
  car_data['NEW'] << c.id if c.new == 1
end

1 Comment

Better: car_data = { 'NEW' => [ ] }. Get it done in one shot.
1
car_data = Car.all.each_with_object(Hash.new { |h, k| h[k] = [] }) do |c, memo|
  memo[c.brand] = c.id
  memo['NEW'] << c.id if c.new == 1
end

or, simpler, let’s create it on the fly if needed:

car_data = Car.all.each_with_object({}) do |c, memo|
  memo[c.brand] = c.id
  (memo['NEW'] ||= []) << c.id if c.new == 1
end

Please also refer to comment by @tadman below, if the NEW key is to be existing in any case.

3 Comments

Probably better with { 'NEW' => [ ] } than the cruft where it optionally initializes it.
@tadman This cruft contains a hint on how to deal with “maybe nil” objects. For the sophisticated initialization there is always variant 1 present.
I know what you're saying, but the difference here is in maybe not initializing the NEW key, which seems like a harmless thing to do by default.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.