将散列阵列转换为散列阵列

问题描述:

我有一个散列阵列数组。将散列阵列转换为散列阵列

items = 
[{ "item_9": 152 }, { "item_2": 139 }, { "item_13": 138 }, { "item_72": 137 }, { "item_125": 140 }, { "item_10": 144 }] 
[{ "item_9": 152 }, { "item_2": 139 }, { "item_13": 138 }, { "item_72": 137 }, { "item_125": 140 }, { "item_10": 146 }] 
[{ "item_9": 152 }, { "item_2": 139 }, { "item_13": 138 }, { "item_72": 137 }, { "item_125": 140 }, { "item_10": 147 }] 
[{ "item_9": 152 }, { "item_2": 139 }, { "item_13": 138 }, { "item_72": 137 }, { "item_125": 140 }, { "item_10": 148 }] 
[{ "item_9": 152 }, { "item_2": 139 }, { "item_13": 138 }, { "item_72": 137 }, { "item_125": 140 }, { "item_10": 153 }] 
. 
. 
. 
[{ "item_9": 152 }, { "item_2": 145 }, { "item_13": 150 }, { "item_72": 154 }, { "item_125": 141 }, { "item_10": 144 }] 
[{ "item_9": 152 }, { "item_2": 145 }, { "item_13": 150 }, { "item_72": 154 }, { "item_125": 141 }, { "item_10": 146 }] 
[{ "item_9": 152 }, { "item_2": 145 }, { "item_13": 150 }, { "item_72": 154 }, { "item_125": 141 }, { "item_10": 147 }] 
[{ "item_9": 152 }, { "item_2": 145 }, { "item_13": 150 }, { "item_72": 154 }, { "item_125": 141 }, { "item_10": 148 }] 
[{ "item_9": 152 }, { "item_2": 145 }, { "item_13": 150 }, { "item_72": 154 }, { "item_125": 141 }, { "item_10": 153 }] 

我希望做的是改变它是哈希数组...

items = 
{"item_9"=>152, "item_2"=>145, "item_13"=>150, "item_72"=>154, "item_125"=>141, "item_10"=>146} 
{"item_9"=>152, "item_2"=>145, "item_13"=>150, "item_72"=>154, "item_125"=>141, "item_10"=>147} 
{"item_9"=>152, "item_2"=>145, "item_13"=>150, "item_72"=>154, "item_125"=>141, "item_10"=>148} 
{"item_9"=>152, "item_2"=>145, "item_13"=>150, "item_72"=>154, "item_125"=>141, "item_10"=>153} 

我相信我可以用这样做...

items.map! { |item| item.reduce({}, :merge) } 

但是,这不是很高效。当你有1.4亿条记录时,至少它不够高效。有一个更好的方法吗?

+0

首先我会尝试:' :更新'而不是':merge'进行就地更新。 – tokland

+0

有趣的是,使用for循环并不能真正帮助任何事情。 –

或许有点长,但它的工作原理更快:

require 'benchmark' 

items = [ 
    [{ item_9: 152 }, { item_2: 139 }, { item_13: 138 }, { item_72: 137 }, { item_125: 140 }, { item_10: 146 }], 
    [{ item_9: 152 }, { item_2: 139 }, { item_13: 138 }, { item_72: 137 }, { item_125: 140 }, { item_10: 147 }], 
    [{ item_9: 152 }, { item_2: 139 }, { item_13: 138 }, { item_72: 137 }, { item_125: 140 }, { item_10: 148 }], 
    [{ item_9: 152 }, { item_2: 139 }, { item_13: 138 }, { item_72: 137 }, { item_125: 140 }, { item_10: 153 }], 
    [{ item_9: 152 }, { item_2: 145 }, { item_13: 150 }, { item_72: 154 }, { item_125: 141 }, { item_10: 144 }], 
    [{ item_9: 152 }, { item_2: 145 }, { item_13: 150 }, { item_72: 154 }, { item_125: 141 }, { item_10: 146 }], 
    [{ item_9: 152 }, { item_2: 145 }, { item_13: 150 }, { item_72: 154 }, { item_125: 141 }, { item_10: 147 }], 
] 

n = 100_000 
Benchmark.bm do |b| 
    b.report do 
    n.times do |i| 
     items.map { |item| item.reduce({}, :merge) } 
    end 
    end 
    b.report do 
    n.times do |i| 
     # the winer 
     items.map { |item| item.reduce({}, :update) } 
    end 
    end 
    b.report do 
    n.times do |i| 
     items.map { |i| i.inject({}) { |f,c| f.update c } } 
    end 
    end 
end 

为@tokland表明,item.reduce({}, :update)还要快:

user  system  total  real 
6.300000 0.080000 6.380000 ( 6.386180) 
1.840000 0.020000 1.860000 ( 1.860073) 
2.220000 0.020000 2.240000 ( 2.237294) 

感谢@tokland

+0

+1,惊人的加速。 –

+0

它比'reduce({},:update)'更快吗?只是说让它更接近原始代码。 – tokland

+0

是的,这是一个非常好的加速。处理1700万条记录需要〜243秒这比其他方式快得多。想给你答案的答案,因为我认为让速度更快的唯一方法是按照我想要的方式构建数据。但那是在我的另一个问题。不幸的是,我要求帮助错误地构建它。 http://stackoverflow.com/questions/13283330/how-do-i-keep-the-hash-associations-when-building-permutations – Altonymous

由于性能问题,它可能是时间for循环yield S以及注意到有关数据有趣的事实,如果有的话。例如,您的数据似乎有许多重复的项目。这是一个规则还是一个巧合?

+0

生成随机数据集只是一个巧合。在做这件事之前,我实际上已经对它进行了重复。 – Altonymous

如果你确定你有一个两级阵列(对内没有其他阵列),每对中只有两个项目,那么使用它会更快,更短:

array = [['A', 'a'], ['B', 'b'], ['C', 'c']] 
hash = Hash[*array.flatten] 

对于两层以上的深层数组,这会给出错误的结果甚至错误(对于某些输入)。

array = [['A', 'a'], ['B', 'b'], ['C', ['a', 'b', 'c']]] 
hash = Hash[*array.flatten] 
# => {"A"=>"a", "B"=>"b", "C"=>"a", "b"=>"c"} 

但是,如果你正在运行的Ruby 1.8.7或更高版本可以传递参数数组#压平,并将它压平深只有一层:

# on Ruby 1.8.7+ 
hash = Hash[*array.flatten(1)] 
# => {"A"=>"a", "B"=>"b", "C"=>["a", "b", "c"]}