AGS
AGS

Reputation: 14498

How do I iteratively add key/value pairs, where each value is an array?

I am iteratively assigning elements to a hash whose values are an array consisting of an integer and an array. A toy example of my current strategy is this (incrementing the first element of the array, and pushing a number to the second element of the array):

aHash = Hash.new([0, []])

[1,3,5,1,1].each do |x|
  aHash[x] = [aHash[x][0] + 1, aHash[x][1] << x]
end

aHash # => {1=>[3, [1, 3, 5, 1, 1]], 3=>[1, [1, 3, 5, 1, 1]], 5=>[1, [1, 3, 5, 1, 1]]}

The incrementing portion of the loop appears to be working, however appending each array is not. The desired hash should look like this:

aHash # => {1=>[3, [1, 1, 1]], 3=>[1, [3]], 5=>[1, [5]]}

I have also tried:

[1,3,5,1,1].each do |x|
  aHash[x] = [aHash.values_at(x)[0][0] + 1, aHash.values_at(x)[0][1] << x]
end

aHash # => {1=>[3, [1, 3, 5, 1, 1]], 3=>[1, [1, 3, 5, 1, 1]], 5=>[1, [1, 3, 5, 1, 1]]}

But am getting this same incorrect result.

That being said, my questions are:

  1. How can I properly initialize this hash, assuming that is my problem, or, if not that...
  2. Properly increment the first element of the hash's value, and append the second element of the hash's value?

Upvotes: 0

Views: 181

Answers (2)

hirolau
hirolau

Reputation: 13901

If I was trying to get the result you are looking for I would use the group_by function.

a = [1,3,5,1,1]
p a.group_by{|x|x} #=> {5=>[5], 1=>[1, 1, 1], 3=>[3]}

And if you really want the format you asked for:

a = [1,3,5,1,1]
a_transformed = a.group_by{|x|x}.map{|x|[x.first,[x.last.size,x.last]]}
p Hash[a_transformed] #=> {1=>[3, [1, 1, 1]], 3=>[1, [3]], 5=>[1, [5]]}

Upvotes: 0

Max
Max

Reputation: 22325

aHash = Hash.new([0, []])

Objects are passed by reference in Ruby. You are creating one array for the default value ([0, []]) and passing a reference to that same array every time you access a missing key.

The solution is to create your default array inside a block, so that it gets reevaluated with each missing key:

aHash = Hash.new { [0, []] }

Upvotes: 2

Related Questions