我有这个哈希:
{"path_1" => [1,2,3], "path_2" => [1,4,5], "path_3" => [1,2,3,4]}
我想从哈希中删除所有“部分”路径。所以path_1
需要去,因为它是path_3
的一部分; [1,2,3]
是[1,2,3,4]
的“未完成”数组。需要从此哈希中删除所有“部分”。
这是我当前的代码,但在处理大型哈希时速度很慢:
# hash sorted by length of value
hash_array = {"path_1" => [1,2,3], "path_2" => [1,4,5], "path_3" => [1,2,3,4]}
# make a separate copy of the hash
cloned_hash_array = hash_array.clone
hash_array.each {|path_index, path|
# delete this path from the cloned hash so it doesn't match itself
cloned_hash_array.delete(path_index)
cloned_hash_array.each{|cloned_path_index, cloned_path|
if cloned_path[0,path.length] == path.clone
hash_array.delete(path_index)
end
}
}
答案 0 :(得分:1)
你可以试试这个,应该快一点(没有双循环)。
h = {"path_1" => [1,2,3], "path_2" => [1,4,5], "path_3" => [1,2,3,4]}
h2 = {}
a = h.sort{|l, r| r[1] <=> l[1]}
puts a.inspect
# => [["path_2", [1, 4, 5]], ["path_3", [1, 2, 3, 4]], ["path_1", [1, 2, 3]]]
last_path = nil
a.each do |key, path|
# now all paths are sorted in descending order.
# if a current path is a prefix for last_path, then discard it.
# otherwise, write it to a result and start comparing next ones against it.
if !last_path || last_path[0, path.length] != path
h2[key] = path
last_path = path
end
end
puts h2.inspect
# => {"path_2"=>[1, 4, 5], "path_3"=>[1, 2, 3, 4]}
答案 1 :(得分:1)
取决于您希望它有多快以及您拥有多少元素。你可以试试这样的东西(看起来很疯狂,但它真的很快):
scatter =
lambda { |tree, path, name|
if path.empty?
tree[:tag] = name
tree[:path] unless tree.has_key?(:path)
else
head, *tail = path
unless tree[:path].has_key?(head)
tree[:path][head] = {:path => {}}
end
scatter[tree[:path][head], tail, name]
end
}
gather =
lambda { |tree|
if tree[:path].empty?
[[tree[:tag], []]]
else
tree[:path].map { |k, v|
gather[v].map do |tag, path|
[tag, [k] + path]
end
}.flatten(1)
end
}
scatter_gather =
lambda { |paths|
tree = {:path => {}}
paths.each do |tag, path|
scatter[tree, path, tag]
end
Hash[gather[tree]]
}
scatter_gather["path_1" => [1,2,3], "path_2" => [1,4,5], "path_3" => [1,2,3,4]]
#=> {"path_2"=>[1, 4, 5], "path_3"=>[1, 2, 3, 4]}
答案 2 :(得分:0)
这个怎么样:
hash_array = {"path_1" => [1,2,3], "path_2" => [1,4,5], "path_3" => [1,2,3,4]}
cloned_hash_array = hash_array.clone
cloned_hash_array.each do |key, value|
hash_array.each do |key2, value2|
if key != key2 and value.length <= value2.length
if value.all? { |i| value2.include?(i) }
cloned_hash_array.delete(key)
break
end
end
end
end
puts cloned_hash_array.inspect