Create hash from variables in loop

9.1k views Asked by At

I want to end up with an array of hashes.

I am starting with an array of codes:

@codes = ['123', '456', '789']

I take each of those codes and hit an API with them and it returns values that I parse into variables in a loop, like so:

@codes.each do |x|
  @y = x.get_some_data
  @brand = @y[brand]
  @size = @y[size]
end

Then I want to put this data into an array of hashes

merged_array = []
final_hash = @codes.map{|code| {:code => code, :brand=> @brand, :size=> @size}
merged_array << final_hash

And in a perfect world, end up with hashes that look like this in the merged_array:

 {:code => '123', :brand=> 'nike', :size=> 8 }
 {:code => '456', :brand=> 'adidas', :size=> 4 }
 {:code => '789', :brand=> 'converse', :size=> 10 }

But when I run my script it maps the codes right, but overwrites the @brand, @size variables and just returns the values of the last loop.

Not sure how to get all my variables into the hashes?

2

There are 2 answers

3
Technaton On BEST ANSWER

In your code example, the variables are all declared as being instance variables, because they're prefixed with @.

However, the variables within the loop are simply working/temporary variables, not instance variables. Additionally, x.get_some_data is probably not working, since x is just the loop variable and contains 456, abc, etc., and not an object with the desired method. Thus, the following code should produce your desired result:

def get_data(codes)
  result = []
  codes.each do |code|
    y = get_some_data(code)
    result << {
      code: code,
      brand: y['brand'],
      size: y['size']
    }
  end
  result
end

This is a very verbose example; you can put the whole logic in map, if the return value of get_some_data permits it.

A more elegant version would utilize Enumerable#each_with_object (the Array class includes Enumereable):

def get_data(codes)
  codes.each_with_object([]) do |code, result|
    y = get_some_data(code)
    result << {
      code: code,
      brand: y['brand'],
      size: y['size']
    }
  end
end

Thanks, Cary Swoveland, for pointing this out!

0
Abhi On

This should do the work

@codes.map{|code| {:code => code, :brand => code.get_some_data['brand'], code.get_some_data['size']}}

But, I'm really not sure what String.get_some_data will give you. Eg:- '123'.get_some_data['brand']