我的层次结构中有一个哈希值,如['country', 'city', 'street', ...]
谁是我树的最后一个儿子的头。
我的数据看起来像
{"country": "france", "city": "paris", "street": "champs elysee"},
{"country": "france", "city": "Lyon", "street": "lyon street"},
{"country": "italy", "city": "rome", "street": "rome street1"},
...
我想将其转换为像
这样的树[
{
"france" => [
{
"paris" => {"champs elysee" => [...]},
"lyon" => {"lyon street1" => [...]}
}
]
},
{
"italy" => [
{
"rome" => {"rome street 1" => [...]},
...
}
]
},
]
能够改变我的等级
我尝试了很多东西,但我找不到任何解决方案......我认为没有正确的方法。
编辑:
这是我的代码(根本不工作),但这是主意。
require 'json'
@hierarchie = ["country", "city", "street"]
f = File.read("./data.json")
@ret = JSON.parse(f)
@tree = []
def render_as_tree
@ret.each do |datum|
ptr = @tree
@hierarchie.each do |h|
if ptr.empty?
ptr << {datum[h] => []}
end
obj = ptr.detect {|d| datum[h]}
ptr = obj[ datum[h] ]
end
end
return @tree
end
puts render_as_tree()
此代码是我的代码的一个小例子。我的代码不是国家/城市/街道,但它更适合理解和解释。
...
表示孩子的数量可能会动态变化。对于这个例子,我可以country/city/district/street/house/...
或country/city
,所以我的最后数据需要是平面数据。
答案 0 :(得分:1)
您可以使用inject
或each_with_object
来浏览数据
data = [
{"country": "france", "city": "paris", "street": "champs elysee"},
{"country": "france", "city": "Lyon", "street": "lyon street"},
{"country": "italy", "city": "rome", "street": "rome street1"},
]
hierarchy = data.each_with_object({}) do |row, hsh|
country = row[:country]
city = row[:city]
street = row[:street]
hsh[country] ||= {}
hsh[country][city] ||= {}
hsh[country][city][street] ||= []
hsh[country][city][street] << "?" # put here anything you need
end
p hierarchy
#=> {"france"=>{"paris"=>{"champs elysee"=>["?"]}, "Lyon"=>{"lyon street"=>["?"]}}, "italy"=>{"rome"=>{"rome street1"=>["?"]}}}
UPD:
def tree(data, hierarchy)
data.each_with_object({}) do |row, hsh|
node = hsh
hierarchy.each do |level|
val = row[level]
node[val] ||= {}
node = node[val]
end
end
end
tree(data, [:country, :city])
#=> {"france"=>{"paris"=>{}, "Lyon"=>{}}, "italy"=>{"rome"=>{}}}
tree(data, [:country, :city, :street])
#=> {"france"=>{"paris"=>{"champs elysee"=>{}}, "Lyon"=>{"lyon street"=>{}}}, "italy"=>{"rome"=>{"rome street1"=>{}}}}
答案 1 :(得分:0)
arr = [{"country": "france", "city": "paris", "street": "champs elysee"},
{"country": "france", "city": "lyon", "street": "rue mandelot"},
{"country": "italy", "city": "rome", "street": "via del corso"},
{"country": "france", "city": "paris", "street": "rue montorgueil"}]
arr.each_with_object({}) {|g,h| ((h[g[:country]] ||={})[g[:city]] ||={})[g[:street]]=['x']}
#=> {"france"=>{"paris"=>{"champs elysee"=>["x"], "rue montorgueil"=>["x"]},
# "lyon"=>{"rue mandelot"=>["x"]}},
# "italy"=>{"rome"=>{"via del corso"=>["x"]}}}
@ fl00r我都返回了一个由嵌套哈希组成的对象,而不是问题中指定的交替哈希和数组。由于每个数组都包含一个哈希值,因此它们没有用处。
答案 2 :(得分:0)
感谢@ProGM,我找到了解决方案!
class Tree
attr_reader :data
def initialize(data)
@data = data
end
def +(other)
Tree.new(deep_merge(@data, other.is_a?(Tree) ? other.data : other))
end
delegate :empty?, to: :data
def replace(other)
@data.replace(other.data)
end
def root
level(0)
end
def levels
output = []
i = -1
while i += 1
current_level = level(i)
break if current_level.all?(&:nil?)
output << current_level
end
output
end
def level(level_number)
all_elements_at_level(@data, level_number)
end
private
def deep_merge(a, b)
case a
when Hash
return merge_hashes(a, b) if b.is_a?(Hash)
return merge_array_hash(b, a) if b.is_a?(Array)
[b, a]
when Array
return merge_arrays(a, b) if b.is_a?(Array)
return merge_array_hash(a, b) if b.is_a?(Hash)
[b] + a
else
return [a, b] if b.is_a?(Hash)
return [a] + b if b.is_a?(Array)
a == b ? a : [a, b]
end
end
def merge_array_hash(a, b)
if a.last.is_a? Hash
a[0...-1] + [merge_hashes(a.last, b)]
else
a + [b]
end
end
def merge_hashes(a, b)
a.deep_merge(b) do |_, this_val, other_val|
deep_merge(this_val, other_val)
end
end
def merge_arrays(a, b)
keys = merge_array_keys(a, b)
hashes = merge_hashes(a.last.is_a?(Hash) ? a.last : {}, b.last.is_a?(Hash) ? b.last : {})
if hashes.empty?
keys
else
(keys - hashes.keys) + [hashes]
end
end
def merge_array_keys(a, b)
(a.reject { |e| e.is_a?(Hash) } + b.reject { |e| e.is_a?(Hash) }).uniq
end
def all_elements_at_level(data, level_number)
return ground_level(data) if level_number == 0
case data
when Hash
data.map { |_, v| all_elements_at_level(v, level_number - 1) }
when Array
data.map { |e| all_elements_at_level(e, level_number) }.flatten
end
end
def ground_level(data)
case data
when Hash
data.keys
when Array
data.map { |e| all_elements_at_level(e, 0) }.flatten
else
data
end
end
end
答案 3 :(得分:-1)
require "json"
data = %|[{"country": "france", "city": "paris", "street": "champs elysee"},{"country": "france", "city": "Lyon", "street": "lyon street"},{"country": "italy", "city": "rome", "street": "rome street1"}]|
parsed = JSON.parse(data)
final = {}
parsed.each {
|h|
if final.has_key? h["country"]
if final[h["country"]].key? h["city"]
final[h["country"]][h["city"]].push h["street"]
else
final[h["country"]][h["city"]] = [ h["street"]]
end
else
final[h["country"]] = {h["city"] => [ h["street"] ]}
end
}
p final