我有一个嵌套的哈希,看起来像这样:
{
'a' => {
'b' => ['c'],
'd' => {
'e' => ['f'],
'g' => ['h', 'i', 'j', 'k']
},
'l' => ['m', 'n', 'o', 'p']
},
'q' => {
'r' => ['s']
}
}
哈希可以有更多的嵌套,但最后一层的值总是数组。
我想把散列“扁平化”成一种格式,在这种格式下,我得到一个数组,这些数组代表所有的键和值,它们构成了嵌套散列的整个“路径/分支”,从最低层的值到散列的顶部。所以有点像从底部开始遍历“树”,同时收集键和值。
对于特定的散列,其输出应该是:
[
['a', 'b', 'c'],
['a', 'd', 'e', 'f'],
['a', 'd', 'g', 'h', 'i', 'j', 'k'],
['a', 'l', 'm', 'n', 'o', 'p'],
['q', 'r', 's']
]
我尝试了许多不同的方法,但到目前为止都没有效果。再次记住,可能会出现比这些更多的级别,所以解决方案必须是通用的。
**注意:**数组的顺序和元素的顺序并不重要。
我做了以下几点,但并没有真正发挥作用:
tree_def = {
'a' => {
'b' => ['c'],
'd' => {
'e' => ['f'],
'g' => ['h', 'i', 'j', 'k']
},
'l' => ['m', 'n', 'o', 'p']
},
'q' => {
'r' => ['s']
}
}
branches = [[]]
collect_branches = lambda do |tree, current_branch|
tree.each do |key, hash_or_values|
current_branch.push(key)
if hash_or_values.kind_of?(Hash)
collect_branches.call(hash_or_values, branches.last)
else # Reached lowest level in dependency tree (which is always an array)
# Add a new branch
branches.push(current_branch.clone)
current_branch.push(*hash_or_values)
current_branch = branches.last
end
end
end
collect_branches.call(tree_def, branches[0])
branches #=> wrong result
7条答案
按热度按时间7cjasjjr1#
正如评论中所暗示的:
看起来很简单。递归地下降到散列,注意你在这个分支中访问的键。当你看到一个数组时,不需要进一步递归。将它附加到键列表并返回
跟踪很容易,只需将临时状态传递给参数中的递归调用。
我的意思是这样的:
这段代码只是打印每个扁平化的路径,但你也可以将它存储在一个数组中。或者甚至修改
tree_flatten
以返回一个现成的数组,而不是一个接一个地产生元素。sqserrrh2#
你可以这样做:
输出将是:
vm0i2vca3#
这当然需要一个递归的解决方案。下面的方法不会改变原始的哈希值。
编码
示例
说明
递归方法执行的操作总是很难解释。根据我的经验,最好的方法是用puts语句来增加代码。然而,这本身是不够的,因为当查看输出时,很难跟踪获得特定结果的递归级别,并将其传递给它本身或返回给它本身的一个版本。解决方案是缩进和取消缩进结果。请注意我构造代码的方式,我使用的几个辅助方法都是相当通用的,因此这种方法可以适用于检查其他递归方法执行的操作。
jtw3ybtb4#
这将返回一个包含所有路径的Array。
为了更好的打印你可以做
pgccezyw5#
请看下面的代码,它会一直递归地调用,直到到达数组值。
这个递归调用会有多个分支,
op
应该是每个分支的单独副本,所以我使用了string,它总是在这里作为一个新对象创建,否则数组就像使用通过引用调用@output
将是您想要的数组。**更新:**键值对可以多于一个字符,所以下面的
nested_array
方法可能会更好。2j4z5cfb6#
这里所有的解都是递归的,下面是一个非递归的解。
代码说明:
解决方案:
pu3pd22g7#
我需要一个与此类似的解决方案。在我的用例中,我希望任何数组都能与之前的“路径”进行置换。我希望编写一些简洁的结构,可以表示“路径”(不一定是文件路径,但可能是消息路由路径),并在需要时进行扩展。一个简单的例子是
我想到的解决方案在下面。
也就是说,如果你想保持你的数组平坦,而不是在它们上面进行置换,你可以修改上面的内容,不再递归,只返回附加到路径上的数组。
注意:我还没有决定方法的名字;很明显,在一天结束的时候,这取决于程序员,但这是一个有趣的问题,在某种意义上,结构是膨胀的,而在另一些意义上,它是扁平的。