how to convert line 1 to line 2
h1 = {"one"=>[1,2,3,4], "two"=>[4,5,6,7], "three"=>[7,8,9,1]}
h2 ={4=>["one","two"],7=>["two","three"],1=>["one","three"]}
CodePudding user response:
h1.each_with_object(Hash.new { |h,k| h[k] = [] }) do |(k,v), h|
v.each { |n| h[n] << k }
end.select { |_,v| v.size > 1 }
#=> {1=>["one", "three"], 4=>["one", "two"], 7=>["two", "three"]}
This uses the form of Hash::new that takes a block and no argument. If h = Hash.new { |h,k| h[k] = [] }
then, possibly after key/value pairs have been added to h
, if h
does not have a key n
, h[n] << n
causes h[n] = []
to be executed prior to h[n] << k
.
I can best explain the calculations by sale code with puts
statements and then executing the code for the example.
h1.each_with_object(Hash.new { |h,k| h[k] = [] }) do |(k,v), h|
puts "\nk = #{k}, v = #{v}, h = #{h}"
v.each do |n|
puts " n = #{n}"
puts " Execute h[#{n}] = [] because h does not have a key #{k}" unless
h.key(n) unless h.key?(n)
h[n] << k
puts " h after h[#{n}] << #{k} = #{h}"
end
end
.tap { |h| puts "\nh before select = #{h}" }
.select { |_,v| v.size > 1 }
#=> {1=>["one", "three"], 4=>["one", "two"], 7=>["two", "three"]}
displays:
k = one, v = [1, 2, 3, 4], h = {}
n = 1
Execute h[1] = [] because h does not have a key one
h after h[1] << one = {1=>["one"]}
n = 2
Execute h[2] = [] because h does not have a key one
h after h[2] << one = {1=>["one"], 2=>["one"]}
n = 3
Execute h[3] = [] because h does not have a key one
h after h[3] << one = {1=>["one"], 2=>["one"], 3=>["one"]}
n = 4
Execute h[4] = [] because h does not have a key one
h after h[4] << one = {1=>["one"], 2=>["one"], 3=>["one"], 4=>["one"]}
k = two, v = [4, 5, 6, 7], h = {1=>["one"], 2=>["one"], 3=>["one"], 4=>["one"]}
n = 4
h after h[4] << two = {1=>["one"], 2=>["one"], 3=>["one"], 4=>["one", "two"]}
n = 5
Execute h[5] = [] because h does not have a key two
h after h[5] << two = {1=>["one"], 2=>["one"], 3=>["one"], 4=>["one", "two"],
5=>["two"]}
n = 6
Execute h[6] = [] because h does not have a key two
h after h[6] << two = {1=>["one"], 2=>["one"], 3=>["one"], 4=>["one", "two"],
5=>["two"], 6=>["two"]}
n = 7
Execute h[7] = [] because h does not have a key two
h after h[7] << two = {1=>["one"], 2=>["one"], 3=>["one"], 4=>["one", "two"],
5=>["two"], 6=>["two"], 7=>["two"]}
k = three, v = [7, 8, 9, 1], h = {1=>["one"], 2=>["one"], 3=>["one"],
4=>["one", "two"], 5=>["two"], 6=>["two"], 7=>["two"]}
n = 7
h after h[7] << three = {1=>["one"], 2=>["one"], 3=>["one"], 4=>["one", "two"],
5=>["two"], 6=>["two"], 7=>["two", "three"]}
n = 8
Execute h[8] = [] because h does not have a key three
h after h[8] << three = {1=>["one"], 2=>["one"], 3=>["one"], 4=>["one", "two"],
5=>["two"], 6=>["two"], 7=>["two", "three"], 8=>["three"]}
n = 9
Execute h[9] = [] because h does not have a key three
h after h[9] << three = {1=>["one"], 2=>["one"], 3=>["one"], 4=>["one", "two"],
5=>["two"], 6=>["two"], 7=>["two", "three"], 8=>["three"], 9=>["three"]}
n = 1
h after h[1] << three = {1=>["one", "three"], 2=>["one"], 3=>["one"],
4=>["one", "two"], 5=>["two"], 6=>["two"], 7=>["two", "three"], 8=>["three"],
9=>["three"]}
h before select = {1=>["one", "three"], 2=>["one"], 3=>["one"], 4=>["one", "two"],
5=>["two"], 6=>["two"], 7=>["two", "three"], 8=>["three"], 9=>["three"]}