簡體   English   中英

Ruby中數組的額外嵌套二級哈希

[英]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
_

使用Enumerable#group_by

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#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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM