2

I'm trying to add different values into an array for the same key into the hash. Instead of making a new instance in the array, my function sum ups the index values of the array elements

def dupe_indices(array)
    hash = Hash.new([])
    array.each.with_index { |ele, idx| hash[ele] = (idx) }
    hash
end

I'm getting this

print dupe_indices(['a', 'b', 'c', 'a', 'c']) => {"a"=>3, "b"=>1, 
"c"=>4}

Expected output

print dupe_indices(['a', 'b', 'c', 'a', 'c']) => { 'a' => [0, 3], 'b' 
=> [1], 'c' => [2, 4] }
1
  • Alternatively ary.each_index.group_by { |i| ary[i] } Commented Jun 17, 2019 at 9:14

1 Answer 1

3

With two small modifications your code willl work.

  1. change hash = Hash.new([]) to hash = Hash.new { |h,k| h[k] = [] }

you should really never use Hash.new([]), see this article for an explanation: https://mensfeld.pl/2016/09/ruby-hash-default-value-be-cautious-when-you-use-it/

  1. Change hash[ele] = (idx) to hash[ele].push(idx)

you don't want to replace the value whenever you encounter a new index, you want to push it to the array.

array = ['a', 'b', 'c', 'a', 'c']

def dupe_indices(array)
    hash = Hash.new { |h,k| h[k] = [] }
    array.each.with_index { |ele, idx| hash[ele].push(idx) }
    hash
end

dupe_indices(array)
# => {"a"=>[0, 3], "b"=>[1], "c"=>[2, 4]}
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you so much! I'm a little bit confused with this line: hash = Hash.new { |h,k| h[k] = [] }, particulary with 'h' argument.
H and k stand for hash and key. When an unknown key gets looked up in the hash, this block is called. You can google for "ruby default hash block" for more explanation, in on the go right now
Timur, each.with_index is generally written each_with_index unless one wants the index to have a base other than zero (e.g., ...each.with_index(1)...). Defining the hash as it is done here is effectively the same as hash = {}; array.each_with_index { |ele, idx| hash[ele] = [] unless hash.key?(ele); hash[ele].push(idx) }; hash. Lastly, you could reduce the body of the method to one line by writing array.each_with_index.with_object(Hash.new { |h,k| h[k] = [] }) { |(ele, idx), hash| hash[ele].push(idx) }.
@TimurShamuradov: "I'm a little bit confused with this line: hash = Hash.new { |h,k| h[k] = [] }, particulary with 'h' argument" – It would be helpful if you could describe what precisely is unclear to you about the documentation of Hash::new. That way, the Ruby developers can improve the documentation so that future developers do not stumble across the same problems as you. Help make the world a better place!

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.