group_by 在 ruby 中有很多标签的项目列表
group_by a list of items which have many tags in ruby
我有一个对象列表,其中可能有 0 个或多个与之相关联的标签。在最简单的情况下,我有一个对象散列和一个标签列表:
collection = {'object1': ['tag1', 'tag2'], 'object2': ['tag1'], 'object3
': ['tag2'], 'object4': []}
所以每个对象可以有很多标签。
我想 group_by 每个标签和 return 这个:
{'tag1': ['object1', 'object2'], 'tag2': ['object1, 'object3'], nil: ['object4']}
(我不介意我们使用 nil 或空字符串或任何模型化“无标签”的对象)
应该这样做:
results = Hash.new
collection.map do |k, v|
v.each do |tag|
results[tag.to_sym] ||= []
results[tag.to_sym] << k unless results[tag.to_sym].include? k
end
if v.empty?
results[nil] ||= []
results[nil] << k unless results[nil].include? k
end
end
results
试试下面的方法:
collection = {'object1': ['tag1', 'tag2'], 'object2': ['tag1'], 'object3': ['tag2'], 'object4': []}
result = {}
collection.map do |object, tags|
if tags.any?
tags.each { |tag| result[tag] ||= []; result[tag] << object }
else
result[nil] ||= []; result[nil] << object
end
end
结果应该是:
2.6.3 :147 > result
=> {"tag1"=>[:object1, :object2], "tag2"=>[:object1, :object3], nil=>[:object4]}
使用 #enumerable#wit_object with Hash#new(*) 将空数组默认为对象:
res = collection.each_with_object(Hash.new([])) do |(obj, tags), h|
tags.each { |tag| h[tag] += [obj] }
h[nil] += [obj] if tags.empty?
end
(*) If obj is specified, this single object will be used for all default values.
collection = {
'object1': ['tag1', 'tag2'], 'object2': ['tag1'], 'object3': ['tag2'],
'object4': []
}
#=> {:object1=>["tag1", "tag2"], :object2=>["tag1"], :object3=>["tag2"],
# :object4=>[]}
我想说两种最 Ruby-like 的方法如下。
#1
collection.each_with_object({}) do |(k,v),h|
v = [nil] if v.empty?
v.each { |s| (h[s] ||= []) << k }
end
#=> {"tag1"=>[:object1, :object2], "tag2"=>[:object1, :object3], nil=>[:object4]}
行
(h[s] ||= []) << k
扩展到
(h[s] = h[s] || []) << k
所以如果 h
没有密钥 s
这将变为
(h[s] = nil || []) << k
(h[s] = []) << k
h[s] = [k]
#2
collection.each_with_object(Hash.new { |h,k| h[k] = [] }) do |(k,v),h|
v = [nil] if v.empty?
v.each { |s| h[s] << k }
end
#=> {"tag1"=>[:object1, :object2], "tag2"=>[:object1, :object3], nil=>[:object4]}
这使用了 Hash::new 的第三种形式,它创建了一个 默认过程 。如果
h = Hash.new(Hash.new { |h,k| h[k] = [] }
和h
没有密钥k
,
h[k] << v
导致要执行的块,之后 h[k] #=> []
,然后是语句
h[k] << v
已完成。
我有一个对象列表,其中可能有 0 个或多个与之相关联的标签。在最简单的情况下,我有一个对象散列和一个标签列表:
collection = {'object1': ['tag1', 'tag2'], 'object2': ['tag1'], 'object3
': ['tag2'], 'object4': []}
所以每个对象可以有很多标签。
我想 group_by 每个标签和 return 这个:
{'tag1': ['object1', 'object2'], 'tag2': ['object1, 'object3'], nil: ['object4']}
(我不介意我们使用 nil 或空字符串或任何模型化“无标签”的对象)
应该这样做:
results = Hash.new
collection.map do |k, v|
v.each do |tag|
results[tag.to_sym] ||= []
results[tag.to_sym] << k unless results[tag.to_sym].include? k
end
if v.empty?
results[nil] ||= []
results[nil] << k unless results[nil].include? k
end
end
results
试试下面的方法:
collection = {'object1': ['tag1', 'tag2'], 'object2': ['tag1'], 'object3': ['tag2'], 'object4': []}
result = {}
collection.map do |object, tags|
if tags.any?
tags.each { |tag| result[tag] ||= []; result[tag] << object }
else
result[nil] ||= []; result[nil] << object
end
end
结果应该是:
2.6.3 :147 > result
=> {"tag1"=>[:object1, :object2], "tag2"=>[:object1, :object3], nil=>[:object4]}
使用 #enumerable#wit_object with Hash#new(*) 将空数组默认为对象:
res = collection.each_with_object(Hash.new([])) do |(obj, tags), h|
tags.each { |tag| h[tag] += [obj] }
h[nil] += [obj] if tags.empty?
end
(*) If obj is specified, this single object will be used for all default values.
collection = {
'object1': ['tag1', 'tag2'], 'object2': ['tag1'], 'object3': ['tag2'],
'object4': []
}
#=> {:object1=>["tag1", "tag2"], :object2=>["tag1"], :object3=>["tag2"],
# :object4=>[]}
我想说两种最 Ruby-like 的方法如下。
#1
collection.each_with_object({}) do |(k,v),h|
v = [nil] if v.empty?
v.each { |s| (h[s] ||= []) << k }
end
#=> {"tag1"=>[:object1, :object2], "tag2"=>[:object1, :object3], nil=>[:object4]}
行
(h[s] ||= []) << k
扩展到
(h[s] = h[s] || []) << k
所以如果 h
没有密钥 s
这将变为
(h[s] = nil || []) << k
(h[s] = []) << k
h[s] = [k]
#2
collection.each_with_object(Hash.new { |h,k| h[k] = [] }) do |(k,v),h|
v = [nil] if v.empty?
v.each { |s| h[s] << k }
end
#=> {"tag1"=>[:object1, :object2], "tag2"=>[:object1, :object3], nil=>[:object4]}
这使用了 Hash::new 的第三种形式,它创建了一个 默认过程 。如果
h = Hash.new(Hash.new { |h,k| h[k] = [] }
和h
没有密钥k
,
h[k] << v
导致要执行的块,之后 h[k] #=> []
,然后是语句
h[k] << v
已完成。