更快地删除数组散列中的值

时间:2015-10-10 17:30:06

标签: ruby hash

我有以下哈希:

new_hash = {
  [1] => [2, 3, 4, 7, 8 ],
  [2] => [3, 5],
  [3] => [5, 6, 7, 8, 9, 10],
  [4] => [],
}

我想选择具有最多元素的密钥,即第三个密钥。

我试过了:

selected_user = new_hash.max_by{|k,v| v.length}.first   

找到包含最多元素的键后,我想删除所有其他元素的值。我想要的结果是:

new_hash = {
  [1] => [2, 3, 4],
  [2] => [3],
  [3] => [5, 6, 7, 8, 9, 10],
  [4] => [],
}

我尝试使用数组删除所有重复的项目,方法是将值推入数组,然后删除2D数组中的所有元素。

for a in 0..new_arr.length-1
    new_arr[a] = new_arr[a] - newer_arr
end

这是可行的,但是大散列的速度非常低。如何提高此操作的速度?

4 个答案:

答案 0 :(得分:1)

new_hash = { [1] => [2, 3, 4, 7, 8 ], [2] => [3, 5], [3] => [5, 6, 7, 8, 9, 10], [4] => [], }

selected_user = new_hash.max_by{|k,v| v.length}.first

selected_values = new_hash[selected_user]

new_hash.each do |k, v|
  next if k == selected_user
  new_hash[k] = v - selected_values
end

puts new_hash

运行时:

{[1]=>[2, 3, 4], [2]=>[3], [3]=>[5, 6, 7, 8, 9, 10], [4]=>[]}

答案 1 :(得分:0)

这样做:

selected_user_key = new_hash.max_by{|k,v| v.length}.first    

# I suggest to use dup to not alter the original new_hash
return_hash = new_hash.dup

# Step 1 - remove the element from the hash
elements_of_selected_user = return_hash.delete(selected_user_key)

# Step 2 - remove the items that are in elements_of_selected_user
return_hash = Hash[return_hash.map{|k,v| [k, v - elements_of_selected_user]}]

# Step 3 - add the element back to the hash
return_hash[selected_user_key] = elements_of_selected_user

这是有效的,因为在Ruby中你可以执行诸如-之类的数组操作:

[1,2,3] - [2] == [1, 3]

答案 2 :(得分:0)

一种方式:

key, value = new_hash.max_by { |_,a| a.size }
new_hash.merge(new_hash) { |_,v| v - value }.update(key=>value)
  #=> {[1]=>[2, 3, 4], [2]=>[3], [3]=>[5, 6, 7, 8, 9, 10], [4]=>[]}

这使用采用块

Hash#merge形式
{ |_,v| v - value }

确定合并散列中每个键的值。

如果两个键的数组大小与其值相同,则结果当然取决于键的顺序(Ruby v1.9 +)。

答案 3 :(得分:0)

很可能它是阵列而不是哈希会减慢你的速度......

使用[1,2,3] - [1,2]时,您正在创建第三个数组,并且在迭代Hash时创建越来越多的对象会调用内存分配,这会降低您的速度。

如果您知道数组的所有成员都是唯一的,我建议您使用集合代替数组,利用Set#subtract方法......

require 'set'
new_hash = {
  [1] => [2, 3, 4, 7, 8 ].to_set,
  [2] => [3, 5].to_set,
  [3] => [5, 6, 7, 8, 9, 10].to_set,
  [4] => [].to_set,
}

selected_user = new_hash.max_by{|k,v| v.length}.first
values = new_hash[selected_user]
new_hash.each {|k, v| v.subtract values unless k == selected_user}

由于内存分配和对象管理的不同,Set对象的创建速度稍慢,但由于您不是使用此过程创建新对象,因此它应该稍微高效 - 特别是对于大型持久性数据结构。

P.S。

您是否有理由在用户ID密钥中使用Arrays?散列键是冻结的,无法更改,因此我没有看到使用数组的附加值(与FixNum相比,这会降低你的速度。)

为什么不使用:

require 'set'
new_hash = {
  1 => [2, 3, 4, 7, 8 ].to_set,
  2 => [3, 5].to_set,
  3 => [5, 6, 7, 8, 9, 10].to_set,
  4 => [].to_set,
}