[英]Nested Hash from Two Arrays in Ruby + Sorting and Filtering by value
[英]Extra nested second level hash of arrays in Ruby
我有这个输入:
Us,1,1,F
Us,1,2,O
Us,2,1,N
Pa,1,1,S
Pa,1,3, D
Pa,1,5,H
Pa,4,7,K
我正在尝试获取数组的哈希(反过来又是数组的哈希)。 我想得到这个哈希:
b = {
"Us" => [
{"1" => [["1", "F"], ["2", "O"]]},
{"2" => [["1", "N"]]}
],
"Pa" => [
{"1" => [["1", "S"], ["3", "D"], ["5", "H"]]},
{"4" => [["7", "K"]]}
]
}
这是我的代码:
a = Hash.new{|hsh, key| hsh[key] = []}
b = Hash.new{|hsh, key| hsh[key] = []}
File.readlines('file.txt').each do |line|
r = line.split(",")
a[r[0] + "°" + r[1]].push [r[2], r[3].strip] # I load hash "a" here
end
a.map{|k, v|
m=k.split("°")
b[m[0]].push [m[1]=> v] # I load hash "b" here
}
哈希键是Column1和Column2中值的唯一组合(Col1 °
Col2),值是Col2(第二级哈希键),Col3和Col4(这两个作为内部数组的元素)之间的关系)。
我几乎得到了结果,但是有一个额外的嵌套。 我得到这个结果:
b = {
"Us"=>[
[{"1"=>[["1", "F"], ["2", "O"]]}],
[{"2"=>[["1", "N"]]}]
],
"Pa"=>[
[{"1"=>[["1", "S"], ["3", "D"], ["5", "H"]]}],
[{"4"=>[["7", "K"]]}]
]
}
请给我一些帮助。
UPDATE
从Cary的建议修改为较短的代码。
a = Hash.new{|hsh, key| hsh[key] = []}
b = Hash.new{|hsh, key| hsh[key] = []}
File.readlines('input').each do |line|
r = line.chomp.split(",")
a[[r[0], r[1]]].push [r[2], r[3]]
end
a.each{|k, v|
b[k[0]].concat [k[1] => v]
}
UPDATE2
即使在Cary的帮助下,我仍然可以获得最终的输出,但我仍在下面说明了为什么要尝试获取数组的哈希,并在数组内部尝试另一个数组哈希。
这是输出。 就像组织书籍索引显示各个部分(“ Us”和“ Pa”),然后显示每个部分的章节(“ Us”分别为1和2,“ Pa”为1和4)。 然后为每个章节显示每个文章及其相关描述,示例文章“ 3”的描述为“ D”,因此“ D”打印在“ 3”旁边,并且文章“ 3”属于章节“ 1” “霸”。
Us
......1
..............1.......F
..............2.......O
......2
..............1.......N
Pa
......1
..............1.......S
..............3.......D
..............5.......H
......4
..............7.......K
感谢您的大力帮助!
您可以通过替换来修复代码
b[m[0]].push [m[1]=>v]
同
b[m[0]] += [m[1]=> v]
要么
b[m[0]].concat [m[1]=> v]
如您所知,它是执行代码后所需的b
值,因此应将b
添加为最后一行。
其他一些观察:
r = line.split(",")
更改为r = line.chomp.split(",")
,则会简化以下行。 a.map { |k,v|...
替换为a.each { |k,v|...
,它更合适并且a.each { |k,v|...
更好。 a[r[0] + "°" + r[1]]...
使我的眼睛受伤。 您无需诉诸于此类骇客。 您可以改写a[r[0], r[1]]...
,删除m=k.split("°")
并将下一行替换为b[k[0]] += [k[1]=> v]
。 您可以通过以下两种方法来做到这一点。 两种方法都使用Hash#transform_values方法,该方法在Ruby v2.4中首次亮相。
str =<<_
Us,1,1,F
Us,1,2,O
Us,2,1,N
Pa,1,1,S
Pa,1,3,D
Pa,1,5,H
Pa,4,7,K
_
str.lines.
map { |line| line.chomp.split(',') }.
group_by(&:shift).
transform_values { |arr| arr.group_by(&:shift).map { |k,v| { k=>v } } }
#=> {"Us"=>[{"1"=>[["1", "F"], ["2", "O"]]}, {"2"=>[["1", "N "]]}],
# "Pa"=>[{"1"=>[["1", "S"], ["3", " D"], ["5", "H"]]}, {"4"=>[["7", "K"]]}]}
步骤如下。
a = str.lines
#=> ["Us,1,1,F\n", "Us,1,2,O\n", "Us,2,1,N \n",
# "Pa,1,1,S\n", "Pa,1,3, D\n", "Pa,1,5,H\n", "Pa,4,7,K\n"]
b = a.map { |line| line.chomp.split(',') }
#=> [["Us", "1", "1", "F"], ["Us", "1", "2", "O"], ["Us", "2", "1", "N "],
# ["Pa", "1", "1", "S"], ["Pa", "1", "3", " D"], ["Pa", "1", "5", "H"],
# ["Pa", "4", "7", "K"]]
c = b.group_by(&:shift)
#=> {"Us"=>[["1", "1", "F"], ["1", "2", "O"], ["2", "1", "N "]],
# "Pa"=>[["1", "1", "S"], ["1", "3", " D"], ["1", "5", "H"],
# ["4", "7", "K"]]}
c.transform_values { |arr| arr.group_by(&:shift).map { |k,v| { k=>v } } }
#=> <the return value shown above>
当执行最后一个表达式时,传递给该块并分配给该块变量的第一个值是:
arr = [["1", "1", "F"], ["1", "2", "O"], ["2", "1", "N "]]
块计算然后返回:
d = arr.group_by(&:shift)
#=> {"1"=>[["1", "F"], ["2", "O"]], "2"=>[["1", "N "]]}
d.map { |k,v| { k=>v } }
#=> [{"1"=>[["1", "F"], ["2", "O"]]}, {"2"=>[["1", "N "]]}]
这使用Hash#update
的形式(又名Hash#merge!
),该形式采用一个块来确定要合并的两个哈希中存在的键的值。 这种update
形式用于两个嵌套级别。
str.lines.each_with_object({}) do |line, h|
s0, s1, s2, s3 = line.chomp.split(',')
h.update(s0=>{ s1=>[[s2, s3]] }) do |_0,oh0,nh0|
oh0.merge(nh0) { |_1,oh1,nh1| oh1+nh1 }
end
end.transform_values { |h| h.map { |k,v| { k=>v } } }
#=> <the return value shown above>
注意, transform_values
前面的代码返回以下内容。
{"Us"=>{"1"=>[["1", "F"], ["2", "O"]], "2"=>[["1", "N"]]},
"Pa"=>{"1"=>[["1", "S"], ["3", " D"], ["5", "H"]], "4"=>[["7", "K"]]}}
下面是此方法的一种变体。
str.lines.each_with_object({}) do |line, h|
s1, s2, s3, s4 = line.chomp.split(',')
h.update(s1=>{ s2=>{ s2=>[[s3, s4]] } }) do |_0,oh0,nh0|
oh0.merge(nh0) do |_1,oh1,nh1|
oh1.merge(nh1) { |_2,oh2,nh2| oh2+nh2 }
end
end
end.transform_values(&:values)
#=> <the return value shown above>
注意, transform_values
前面的代码返回以下内容。
h = {"Us"=>{"1"=>{"1"=>[["1", "F"], ["2", "O"]]}, "2"=>{"2"=>[["1", "N "]]}},
"Pa"=>{"1"=>{"1"=>[["1", "S"], ["3", " D"], ["5", "H"]]}, "4"=>{"4"=>[["7", "K"]]}}}
transform_values(&:values)
将"Us"
和"Pa"
(即哈希)的值转换为这些哈希(也是哈希)的值的数组,即
[{"1"=>[["1", "F"], ["2", "O"]]}, {"2"=>[["1", "N "]]}]
键"Us"
和
[{"1"=>[["1", "S"], ["3", " D"], ["5", "H"]]}, {"4"=>[["7", "K"]]}]
为"Pa"
。 这是因为我们希望"Us"
和"Pa"
的值是散列数组,所以我们需要一些奇怪的表达式
s1=>{ s2=>{ s2=>[[s3, s4]] } }
如果我们希望将"Us"
和"Pa"
的值设为一个我们可以编写的哈希值
s1=>{ s2=>[[s3, s4]] }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.