我在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
我看到“Accessing elements of nested hashes in ruby”,但似乎没有意义。
答案 0 :(得分:4)
我知道你要求一个基于循环的解决方案,但是如果你愿意在标准库中使用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!
答案 1 :(得分:2)
我认为这就是你所需要的:
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
答案 2 :(得分:1)
" Accessing elements of nested hashes in ruby"解决了类似的问题,但有很大的不同:在那个例子中,OP知道他在寻找什么样的钥匙。在您的情况下,在我看来,您只是尝试访问列表中的所有值,因此在其他问题中提交的答案并不完全适用。
如果你要做的只是访问数组中的元素,你可以用不同的方式处理它。我的特殊方法不在for
循环中(for
循环甚至不在Ruby中使用,请参阅" for vs each in Ruby"以获取更多信息),但使用递归方法。您创建一个接受参数的函数。如果它是一个数组,它将打印元素,否则我们假设它是一个哈希,并且每个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)
或者,如果您了解blocks,您可以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 }
答案 3 :(得分:0)
您不需要获取第一级哈希的密钥,然后使用密钥获取值 - 因为您可以直接获取值:
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
答案 4 :(得分:0)
我使用了修改过的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
感谢所有人,我会在以后尝试其他答案。