Ruby Hash With Duplicate Keys

Ruby Hash with duplicate keys?

This would kinda defeat the purpose of a hash, wouldn't it?

If you want a key to point to multiple elements, make it point to an array:

h = Hash.new { |h,k| h[k] = [] }
h[:foo] << :bar
h #=> {:foo=>[:bar]}
h[:foo] << :baz
h #=> {:foo=>[:bar, :baz]}

How to detect duplicate keys in hash and add prefix to the duplicate?

It seems straight forward Have attached code snippet

names = %w[David John Alex Sam Caleb David John Alex Sam]
numbers = %w[1 2 3 4 5 6 7 8 9]

key_pair = {}
names.each_with_index do |name, index|
name = "A-#{name}" if key_pair[name]
key_pair[name] = numbers[index]
end

It generates the expected output:

{"David"=>"1", "John"=>"2", "Alex"=>"3", "Sam"=>"4", "Caleb"=>"5", "A-David"=>"6", "A-John"=>"7", "A-Alex"=>"8", "A-Sam"=>"9"}

Finding duplicate keys across hashes?

You could build another hash to store each key and its hashes:

keys = Hash.new { |hash, key| hash[key] = [] }
a.each_key { |k| keys[k] << :a }
b.each_key { |k| keys[k] << :b }
c.each_key { |k| keys[k] << :c }

More precisely, keys stores an array of symbols. It looks like this after running the above code:

keys
#=> {"A"=>[:a, :b],
# "B"=>[:a, :b],
# "C"=>[:a],
# "D"=>[:b, :c],
# "E"=>[:b, :c],
# "F"=>[:c]}

To get your expected output:

keys.each do |key, hashes|
next if hashes.size < 2
hashes.each { |hash| puts "#{key} is also in #{hash}" }
end

Prints:

A is also in a
A is also in b
B is also in a
B is also in b
D is also in b
D is also in c
E is also in b
E is also in c

How to reduce array of hashes with duplicate keys to nested hash?

def combine(arr)
arr.group_by {|g|g[:foo]}.map {|_,a|{foo: a.first[:foo], bar: a.map {|g| g[:bar]}}}
end

combine arr_with_dup_hsh_keys
#=> [{:foo=>"dup", :bar=>[1, 2, 3, 4, 5]}]

arr_with_dup_hsh_keys1 = [
{ foo: "dup", bar: 1 },
{ foo: "dup", bar: 2 },
{ foo: "soup", bar: 3 },
{ foo: "dup", bar: 4 },
{ foo: "soup", bar: 5 }
]

combine arr_with_dup_hsh_keys1
#=> [{:foo=>"dup", :bar=>[1, 2, 4]}, {:foo=>"soup", :bar=>[3, 5]}]

See Enumerable#group_by and note that

arr_with_dup_hsh_keys1.group_by { |g| g[:foo] }
#=> {"dup"=> [{:foo=>"dup", :bar=>1}, {:foo=>"dup", :bar=>2},
# {:foo=>"dup", :bar=>4}],
# "soup"=>[{:foo=>"soup", :bar=>3}, {:foo=>"soup", :bar=>5}]}

You could alternatively write the following.

def combine(arr)
arr.each_with_object({}) do |g,h|
f = g.merge(bar: [g[:bar]])
h.update(f[:foo]=>f) { |_,o,n| { foo: o[:foo], bar: o[:bar]+n[:bar] } }
end.values
end

combine arr_with_dup_hsh_keys1
#=> [{:foo=>"dup", :bar=>[1, 2, 4]}, {:foo=>"soup", :bar=>[3, 5]}]

This uses the form of Hash#update (aka merge!) that employs a block to determine the values of keys that are present in both hashes being merged. See the doc for an explanation of the three block variables (the first being the common key, which I've represented with an underscore to signify that it's not used in the block calculation).

Ruby - Iterate over array of hashes and sum/compact the values of duplicate keys

What's wrong with a straightforward iteration through all the items?

arr = [{"94838"=>30.0}, {"94916"=>2.0}, {"94916"=>10.0}]

hsh = Hash.new(0) # Default value for each key is zero

# For each hash in arr, iterate through each key/value pair and
# increment the destination total associated with the key by the
# current value. Can use increment because of the zero default.
arr.each { |h| h.each { |k, v| hsh[k] += v } }
p hsh # Produces {"94838"=>30.0, "94916"=>12.0} as desired

Which value for a duplicate key is ignored in a Ruby hash?

The last one overwrites the previous values. In this case, "value3" becomes the value for :keyone. This works just as the same with merge. When you merge two hashes that have the same keys, the value in the latter hash (not the receiver but the argument) overwrites the other value.

In ruby how can we merge two given hash into single hash and replace duplicate key value with greater of both the value

hash1 = { "a" => "123", "b" => "432" }

hash2 = { "a" => "439", "c" => "987" }

Code

h = hash1.merge(hash2) do |k, f, s|
f.to_i > s.to_i ? f : s
end
p h

Output

{"a"=>"439", "b"=>"432", "c"=>"987"}


Related Topics



Leave a reply



Submit