簡體   English   中英

如何獲取紅寶石中復雜的嵌套哈希的元素?

[英]How do I get the elements of a complex nested hash in ruby?

我在Ruby程序中有以下嵌套哈希。 如何編寫for循環,最終打印出每個數組中包含的元素?

alternatives = {
  "JAVA" => {
    "/usr/bin" => [
      "java", "keytool", "orbd", "pack200", "rmid",
      "rmiregistry", "servertool", "tnameserv", "unpack200"
    ],
    "/usr/lib" => [
      "jre", "jre_exports" 
    ],
    "/usr/share" => [
      "java.1", "keytool.1", "orbd.1", "pack200.1", "rmid.1",
      "rmiregistry.1", "servertool.1", "tnameserv.1", "unpack200.1"
    ]
  },
  "JDK" => {
    "/usr/bin" => [
      "javac", "appletviewer", "apt", 
      "extcheck", "jar", "jarsigner", "javadoc", "javah", "javap", 
      "jconsole", "jdb", "jhat", "jinfo", "jmap", "jps", 
      "jrunscript", "jstack", "jstat", "jstatd", "native2ascii",
      "policytool", "rmic", "schemagen", "servialver", "wsgen",
      "wsimport", "xjc" 
    ],
    "/usr/lib" => [
      "java_sdk", "java_sdk_exports"
    ],
    "/usr/share/man/man1" => [
      "javac.1", "appletviewer.1", "apt.1", 
      "extcheck.1", "jar.1", "jarsigner.1", "javadoc.1", "javah.1",
      "javap.1", "jconsole.1", "jdb.1", "jhat.1", "jinfo.1", "jmap.1",
      "jps.1", "jrunscript.1", "jstack.1", "jstat.1", "jstatd.1",
      "native2ascii.1", "policytool.1", "rmic.1", "schemagen.1",
      "servialver.1", "wsgen.1", "wsimport.1", "xjc" 
    ]
  }
}

這是我想要做的偽代碼

alternatives.each do |first_level_keys| # Gets the JAVA, JDK keys
  first_level_keys.each do |second_level_keys| # Gets the /usr/... keys
    second_level_keys.each do |array|
      array.each do |elem|
        puts "elem: " + elem
      end
    end
  end
end

我看到“ 訪問紅寶石中嵌套的哈希元素 ”,但似乎沒有任何意義。

我知道您要求基於循環的解決方案,但是如果您願意在標准庫中使用Hash和Array方法,則沒有必要。

這是我的方法:

alternatives.values.collect(&:values).flatten

說明:

  • .values刪除鍵,為您提供哈希數組: [{'usr/bin' => [...], 'usr/lib' => [...]}, ...]
  • .collect(&:values)接受該哈希數組,然后再次刪除鍵,從而為您提供一個字符串數組數組 ,例如: [[["java",...],[jre, ...]], ...]
  • .flatten將數組轉換為一維字符串數組。

我會加uniq.sort! 用於刪除所有重復項並按字母順序對結果進行排序,除非您想要重復項(然后刪除uniq

alternatives.values.collect(&:values).flatten.uniq.sort!

我認為這就是您所需要的:

alternatives.each_value {|h| h.each_value {|a| a.each {|e| puts "elem: #{e}"}}}
elem: java
elem: keytool
elem: orbd
elem: pack200
...
elem: wsgen.1
elem: wsimport.1
elem: xjc

如果對象具有嵌套的數組和哈希值,且嵌套級別有所不同,則可以按以下方式打印本身不是數組或哈希值的所有值。 對於散列中的key-value對,如果它不是數組或哈希,則將打印value

def print_innermost(o)
  case o
  when Hash then  o.each { |_,v| print_innermost(v) }
  when Array then o.each { |e|   print_innermost(e) }
  else puts "elem: #{o}"
  end
end

print_innermost(alternatives)
elem: java
elem: keytool
elem: orbd
elem: pack200
...
elem: wsgen.1
elem: wsimport.1
elem: xjc

alternatives = [{a: {b: {c: [1,2], d: {e: [3,4], f: 5}}}}, [{g: [6,7]}], 8]

print_innermost(alternatives)
elem: 1
elem: 2
elem: 3
elem: 4
elem: 5
elem: 6
elem: 7
elem: 8

訪問紅寶石中嵌套的哈希元素 ”解決了一個類似的問題,但有很大的不同:在該示例中,OP知道他要尋找的密鑰。 在您的情況下,在我看來您只是在嘗試訪問列表中的所有值,因此在其他問題中提交的答案並不完全適用。

如果您只是想訪問數組中的元素,則可以采用不同的方法。 我的特定方法不是在for循環中(在Ruby中甚至沒有使用for循環,有關更多信息,請參見“ for vs vs Ruby中的 for”),但是使用了遞歸方法。 您創建一個接受參數的函數。 如果它是一個數組,它將打印元素,否則我們假定它是一個Hash,並且函數將對每個value調用(我們只是忽略鍵)

該代碼將是:

def get_elements(obj)
  if obj.is_a?(Array)
    obj.each {|element| puts "elem:" + element }
  else
    obj.each {|key, value| get_elements(value) }
  end
end

get_elements(alternatives)

或者,如果您了解 ,則可以yield元素,因此可以在代碼的另一部分中對它們進行任何處理

def get_elements(obj)
  if obj.is_a?(Array)
    obj.each {|element| yield element }
  else
    obj.each {|key, value| get_elements(value) }
  end
end

get_elements(alternatives) {|elem| puts "elem:" + elem }

您不需要獲取第一級哈希的鍵,然后使用鍵來獲取值-因為您可以直接獲取值:

alternatives.values.each do |hash| # Gets the values for JAVA, JDK keys
  hash.values.each do |arr| # Gets the values for the /usr/... keys
    arr.each do |elmt|
      puts "elem: " + elmt
    end
  end
end

如果您的哈希具有不同級別的嵌套,則遞歸是答案,盡管很難學習遞歸。

警告! 遞歸前進!

def get_arrays(hash)
  results = []

  hash.values.each do |value|
    case value
      when Hash
        get_arrays(value).each do |elmt|
          results << elmt
        end
      when Array
        results << value
    end

  end

  results
end


h = {
  a: [1, 2],
  b: 100,
  c: {
       d: [3, 4, 5],
       e: { f: [6, 7] }
     },
  j: { 
       k: [8, 9], 
       l: [10, 11, 12]
     },
}



results = get_arrays(h)
p results

results.each do |arr|
  arr.each do |elmt|
    print "#{elmt} "
  end
  puts 
end


--output:--
[[1, 2], [3, 4, 5], [6, 7], [8, 9], [10, 11, 12]]
1 2 
3 4 5 
6 7 
8 9 
10 11 12 

我使用了經過修改的7stud答案。

由於我還需要鍵的值(例如,JAVA,JDK,/ usr / ....,因此我結束了此操作:

alternatives.keys.each do |alt_keys| # Gets the values for JAVA, JDK keys
  alternatives[alt_keys].each do |arr| # Gets the values for the /usr/... keys
    puts "array key: " + arr.to_s
    alternatives[alt_keys][arr].each do |elmt|
      puts "elem: " + elmt
    end
  end
end

感謝所有人,我將在稍后嘗試其他答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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