1

Given the following array of hashes, how can I make a new hash with friend_id as the key and dist the value?

results = [
 {"user_id"=>"18", "friend_id"=>"17", "dist"=>"1"},
 {"user_id"=>"18", "friend_id"=>"42", "dist"=>"1"},
 {"user_id"=>"18", "friend_id"=>"43", "dist"=>"1"},
 {"user_id"=>"18", "friend_id"=>"46", "dist"=>"2"}
]

desired_hash = {"17" => "1", "42" => "1", "43" => "1", "46" => "2"}

I've tried map but the values are then in an array. I also tried to flatten that result but it flattened the key instead of the value

5 Answers 5

2
results.each_with_object({}) { |g,h| h[g["friend_id"]] = g["dist"] }

or

results.each_with_object({}) { |g,h| h.update(g["friend_id"]=> g["dist"]) }
Sign up to request clarification or add additional context in comments.

Comments

1

For this use case, I think it would be simpler and more readable to just use #each:

desired_hash = Hash.new
results.each {|h| desired_hash[h["friend_id"]] = h["dist"]}

Then, desired_hash is:

#=> {"17"=>"1", "42"=>"1", "43"=>"1", "46"=>"2"} 

Comments

1

You can use Enumerable#inject method.

results.inject({}) {|sum, e| sum.merge({e["friend_id"] => e["dist"]})}
# => {"17"=>"1", "42"=>"1", "43"=>"1", "46"=>"2"}

3 Comments

merge on each iteration is quite inefficient.
Why ? Could you please tell me the reason?
h1 = { :a => 1 } ; h2 = { :b => 2 } ; n = 5000000 ; Benchmark.bm do |x| x.report { for i in 1..n; h1.merge h2; end } ; x.report { n.times do ; h1[:b] = h2[:b]; end } ; end5.870000 vs. 0.660025. The reason: hash is updated on every merge.
1
results.map {|h| [h['friend_id'], h['dist']]} .to_h

Although I probably like @CarySwoveland 's answer better, on the lines of:

results.each_with_object({}) {|h, n| n[h['friend_id']] = h['dist']}

Comments

1

Simply:

desired_hash = Hash[results.map{ |h| [ h['friend_id'], h['dist']] }]

or as Victor suggests

desired_hash = Hash[results.map{ |x| x.values_at('friend_id', 'dist') }]

2 Comments

I like this approach but you would have to set a new variable to results and use that in the map method instead. As it is, this mutates results array by adding the desired_hash to it: [{"user_id"=>"18", "friend_id"=>"17", "dist"=>"1"}, {"user_id"=>"18", "friend_id"=>"42", "dist"=>"1"}, {"user_id"=>"18", "friend_id"=>"43", "dist"=>"1"}, {"user_id"=>"18", "friend_id"=>"46", "dist"=>"2"}]
h.values_at('friend_id', 'dist') is probably easier

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.