我有一个称为events
的哈希数组:
events = [
{:name => "Event 1", :date => "2019-02-21 08:00:00", :area => "South", :micro_area => "A"},
{:name => "Event 2", :date => "2019-02-21 08:00:00", :area => "South", :micro_area => "A"},
{:name => "Event 3", :date => "2019-02-21 08:00:00", :area => "South", :micro_area => "B"},
{:name => "Event 4", :date => "2019-02-21 08:00:00", :area => "South", :micro_area => "B"},
{:name => "Event 5", :date => "2019-02-21 08:00:00", :area => "North", :micro_area => "A"},
{:name => "Event 6", :date => "2019-02-21 08:00:00", :area => "North", :micro_area => "A"},
{:name => "Event 7", :date => "2019-02-21 08:00:00", :area => "North", :micro_area => "B"},
{:name => "Event 8", :date => "2019-02-21 08:00:00", :area => "North", :micro_area => "B"}
]
我想知道如何首先group_by
,然后date
,然后area
micro_area
,最后以单个散列数组结束,例如:
[
{
"2019-02-21 08:00:00": {
"South": {
"A": [
{:name=>"Event 1", :date=>"2019-02-21 08:00:00", :area=>"South", :micro_area=>"A" },
{:name=>"Event 2", :date=>"2019-02-21 08:00:00", :area=>"South", :micro_area=>"A" }
],
"B": [
{:name=>"Event 3", :date=>"2019-02-21 08:00:00", :area=>"South", :micro_area=>"B" },
{:name=>"Event 4", :date=>"2019-02-21 08:00:00", :area=>"South", :micro_area=>"B" }
]
},
"North": {
"A": [
{:name=>"Event 5", :date=>"2019-02-21 08:00:00", :area=>"North", :micro_area=>"A" },
{:name=>"Event 6", :date=>"2019-02-21 08:00:00", :area=>"North", :micro_area=>"A" }
],
"B": [
{:name=>"Event 7", :date=>"2019-02-21 08:00:00", :area=>"North", :micro_area=>"B" },
{:name=>"Event 8", :date=>"2019-02-21 08:00:00", :area=>"North", :micro_area=>"B" }
]
}
}
}
]
尝试events.group_by { |r| [r[:date], r[:area], r[:micro_area]] }
似乎不太符合我的期望。
答案 0 :(得分:7)
我认为,以下内容将为您服务
events = [
{ name: 'Event 1', date: '2019-02-21 08:00:00', area: 'South', micro_area: 'A' }
]
events.group_by { |x| x[:date] }.transform_values do |v1|
v1.group_by { |y| y[:area] }.transform_values do |v2|
v2.group_by { |z| z[:micro_area] }
end
end
# {
# "2019-02-21 08:00:00"=>{
# "South"=>{
# "A"=>[
# {:name=>"Event 1", :date=>"2019-02-21 08:00:00", :area=>"South", :micro_area=>"A"}
# ]
# }
# }
# }
答案 1 :(得分:4)
另一种选择是遍历哈希时构建嵌套结构:
events.each_with_object({}) do |event, result|
d, a, m = event.values_at(:date, :area, :micro_area)
result[d] ||= {}
result[d][a] ||= {}
result[d][a][m] ||= []
result[d][a][m] << event
end
答案 2 :(得分:3)
另一个选择是像在问题中一样对它们进行分组。然后从用作键的数组构建嵌套结构。
# build an endless nested structure
nested = Hash.new { |hash, key| hash[key] = Hash.new(&hash.default_proc) }
# group by the different criteria and place them in the above nested structure
events.group_by { |event| event.values_at(:date, :area, :micro_area) }
.each { |(*path, last), events| nested.dig(*path)[last] = events }
# optional - reset all default procs
reset_default_proc = ->(hash) { hash.each_value(&reset_default_proc).default = nil if hash.is_a?(Hash) }
reset_default_proc.call(nested)
以上内容将答案留在nested
变量中。
参考:
Hash::new
创建嵌套哈希。Hash#default_proc
获取哈希的默认proc。Hash#default=
将哈希默认值重置回nil
。Hash#dig
遍历嵌套结构,直到最后一个节点。Hash#[]=
将最后一个节点设置为等于分组事件。path
中,并以#dig
的内容作为参数调用path
。答案 3 :(得分:0)
这是一种递归解决方案,它将处理任意级别的嵌套和任意分组对象。
def hashify(events, grouping_keys)
return events if grouping_keys.empty?
first_key, *remaining_keys = grouping_keys
events.group_by { |h| h[first_key] }.
transform_values { |a|
hashify(a.map { |h|
h.reject { |k,_| k == first_key } },
remaining_keys) }
end
在使用来自问题的示例数据执行此操作之前,我们将一个具有不同日期的哈希添加到events
。
events <<
{ :name=>"Event 8", :date=>"2018-12-31 08:00:00",
:area=>"North", :micro_area=>"B" }
grouping_keys = [:date, :area, :micro_area]
hashify(events, grouping_keys)
#=> {"2019-02-21 08:00:00"=>{
# "South"=>{
# "A"=>[{:name=>"Event 1"}, {:name=>"Event 2"}],
# "B"=>[{:name=>"Event 3"}, {:name=>"Event 4"}]
# },
# "North"=>{
# "A"=>[{:name=>"Event 5"}, {:name=>"Event 6"}],
# "B"=>[{:name=>"Event 7"}, {:name=>"Event 8"}]
# }
# },
# "2018-12-31 08:00:00"=>{
# "North"=>{
# "B"=>[{:name=>"Event 8"}]
# }
# }
# }
hashify(events, [:date, :area])
#=> {"2019-02-21 08:00:00"=>{
# "South"=>[
# {:name=>"Event 1", :micro_area=>"A"},
# {:name=>"Event 2", :micro_area=>"A"},
# {:name=>"Event 3", :micro_area=>"B"},
# {:name=>"Event 4", :micro_area=>"B"}
# ],
# "North"=>[
# {:name=>"Event 5", :micro_area=>"A"},
# {:name=>"Event 6", :micro_area=>"A"},
# {:name=>"Event 7", :micro_area=>"B"},
# {:name=>"Event 8", :micro_area=>"B"}
# ]
# },
# "2018-12-31 08:00:00"=>{
# "North"=>[
# {:name=>"Event 8", :micro_area=>"B"}
# ]
# }
# }