如何删除哈希数组中的部分?

时间:2012-02-01 18:12:24

标签: ruby arrays hash

我有这个哈希:

{"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
  }
}

3 个答案:

答案 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