Jasmine Lognnes Jasmine Lognnes - 4 months ago 13
Ruby Question

Where does the extra array come from?

This question is a continuation of this answer.

Below I am trying to reproduce the answer with the real data structure, but I get an extra array for some reason and the elements are swapped.


The two outputs should be the same, so can anyone see what I am doing wrong?

This is correct:

require 'pp'

a = {"A"=>1, "B"=>1, "C"=>1}
b = {"A"=>1, "B"=>1, "D"=>1, "E"=>1}
c = {"D"=>1, "E"=>1, "F"=>1}

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 }
pp keys

which gives

{"A"=>[:a, :b],
"B"=>[:a, :b],
"D"=>[:b, :c],
"E"=>[:b, :c],

Here is the real data structure,

groups = {
"a" => {"A"=>1, "B"=>1, "C"=>1},
"b" => {"A"=>1, "B"=>1, "D"=>1, "E"=>1},
"c" => {"D"=>1, "E"=>1, "F"=>1}

keys2 = Hash.new { |hash, key| hash[key] = [] }
groups.each { |k,v| keys2[k] << v.keys }
pp keys2

which gives the incorrect output

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


Since your innermost structure hasn't changed, the each_key part should be almost identical, i.e.:

a.each_key { |k| keys[k] << :a }

But a now refers to one of your nested hashes and :a to its name:

hash.each_key { |k| keys2[k] << name }

name and hash refer to the keys and values in group:

groups = {
  "a" => {"A"=>1, "B"=>1, "C"=>1},
# ^^^    ^^^^^^^^^^^^^^^^^^^^^^^^
# name            hash

(Note that you can pick any variable name, name and hash are just examples.)

Putting it all together:

require 'pp'

keys2 = Hash.new { |hash, key| hash[key] = [] }

groups.each do |name, hash|
  hash.each_key { |k| keys2[k] << name }

pp keys2


{"A"=>["a", "b"],
 "B"=>["a", "b"],
 "D"=>["b", "c"],
 "E"=>["b", "c"],