基于特定键/值从哈希中删除元素的最快方法

时间:2014-11-16 20:18:13

标签: ruby

我有{strong>大 order_id字符串数组:

order_ids = ["1", "2", "5", ...]

我还有一个数组的order哈希:

orders = [{order_id: "1", name: "John"}, {order_id: "3", name: "Bob"}, ...]

orders_ids表示我需要从orders数组中删除的订单。因此,在上面的示例中,我需要删除{order_id: "1", name: "John"}。但是数组的大小可以是1M +,所以我需要一种更好的方法,而不是逐个遍历数组。

3 个答案:

答案 0 :(得分:2)

除非您计划将数据重新组织成某种树或堆栈(转换时会占用大量内存),否则最好使用#reject方法进行分割和征服。

orders = [{order_id: "1", name: "John"}, {order_id: "3", name: "Bob"}]

order_ids = ["1", "2", "5"]

orders.reject { |val| order_ids.include?(val[:order_id]) }

输出:

{:order_id=>"3", :name=>"Bob"}

答案 1 :(得分:2)

如果您可以从order_idsorders数组中删除元素,并假设您的orders数组不包含重复的ID,则可以从两个数组中删除项目以进行制作包含检查更快:

order_ids = %w[1 3 5 7 9]
orders = [
  {order_id: "1", name: "Abe"},
  {order_id: "2", name: "Bob"},
  {order_id: "3", name: "Clara"},
  {order_id: "4", name: "Daniel"},
  {order_id: "5", name: "Erika"}
]

orders.delete_if do |order|
  break if order_ids.empty?
  index = order_ids.index(order[:order_id])
  order_ids.slice!(index) unless index.nil?
end

p orders     #=> [{:order_id=>"2", :name=>"Bob"}, {:order_id=>"4", :name=>"Daniel"}]
p order_ids  #=> ["7", "9"]

还可以考虑将order_ids设为Set,这是进行包含检查的更好选择。此实现可能比前一个更快:

require "set"

# Convert `order_ids` to a set in order to make inclusion checks faster
order_ids = %w[1 3 5 7 9].to_set

# `orders` is the same array as in the previous example

orders.delete_if do |order|
  break if order_ids.empty?
  order_ids.delete? order[:order_id]
end

p orders     #=> [{:order_id=>"2", :name=>"Bob"}, {:order_id=>"4", :name=>"Daniel"}]
p order_ids  #=> #<Set: {"7", "9"}>

答案 2 :(得分:0)

如果您愿意花一点额外的内存,可以将其减少为线性时间操作。

order_map = orders.each_with_object({}) {|order, obj| obj[order["order_id"]] = order }
orders.each {|order| order_map.delete order }
filtered_orders = order_map.values