Most Efficient way to Recursively Flatten Nested Array to Dot-separated string in Ruby?
I want to convert something like this:
class NestedItem
attr_accessor :key, :children
def initialize(key, &block)
self.key = key
self.children = []
self.instance_eval(&block) if block_given?
end
def keys
[key] + children.keys
end
end
root = NestedItem.new("root") do
children << NestedItem.new("parent_a") do
children << NestedItem.new("child_a")
children << NestedItem.new("child_c")
end
children << NestedItem.new("parent_开发者_JAVA百科b") do
children << NestedItem.new("child_y")
children << NestedItem.new("child_z")
end
end
require 'pp'
pp root
#=>
# #<NestedItem:0x1298a0
# @children=
# [#<NestedItem:0x129814
# @children=
# [#<NestedItem:0x129788 @children=[], @key="child_a">,
# #<NestedItem:0x12974c @children=[], @key="child_c">],
# @key="parent_a">,
# #<NestedItem:0x129738
# @children=
# [#<NestedItem:0x129698 @children=[], @key="child_y">,
# #<NestedItem:0x12965c @children=[], @key="child_z">],
# @key="parent_b">],
# @key="root">
Into this:
root.keys #=>
[
"root",
"root.parent_a",
"root.parent_a.child_a",
"root.parent_a.child_c",
"root.parent_b",
"root.parent_b.child_y",
"root.parent_b.child_z",
]
...using a recursive method.
What's the simplest way to go about this?
Update
I did this:
def keys
[key] + children.map(&:keys).flatten.map do |node|
"#{key}.#{node}"
end
end
Anything better?
Would Array.flatten work for you?
self.children.flatten
should return the flattened results.
Yes, .flatten
will produce what I think you really want.
But if you want exactly the string output you typed, this will do it:
def keys x
here = key
here = x + '.' + here if x
[ here ] + children.inject([]) { |m,o| m += o.keys here }
end
pp root.keys nil
Or, alternatively, replace the last line in #keys with:
([ here ] + children.map { |o| o.keys here }).flatten
精彩评论