对于这个数组:
items = [[60, 3], [60, 3], [276, 2], [276, 2], [48, 2], [207, 2], [46, 2],
[60, 2], [280, 2], [207, 1], [48, 1], [112, 1], [60, 1], [207, 1], [112, 1],
[276, 1], [48, 1], [276, 1], [48, 1], [276, 1], [276, 1], [278, 1], [46, 1],
[48, 1], [279, 1], [207, 1]]
我想在每个子阵列的第一个位置组合常用数字,并将数字加在第二个位置。
例如,您会看到前四个子阵列是:[60, 3], [60, 3], [276, 2], [276, 2]
这将成为:[60,6], [276,4]
等等。
答案 0 :(得分:9)
试试这个
items.
group_by {|i| i[0]}.
map{|key, value| [key,value.inject(0){|sum, x| sum + x[1]}]}
首先,使用group_by创建一个哈希,其键是每个数组的第一个元素。所以我们有
{
60=>[[60, 3], [60, 3], [60, 2], [60, 1]],
276=>[[276, 2], [276, 2], [276, 1], [276, 1], [276, 1], [276, 1]],
48=>[[48, 2], [48, 1], [48, 1], [48, 1], [48, 1]],
207=>[[207, 2], [207, 1], [207, 1], [207, 1]],
46=>[[46, 2], [46, 1]],
280=>[[280, 2]],
112=>[[112, 1], [112, 1]],
278=>[[278, 1]],
279=>[[279, 1]]
}
然后使用map方法循环哈希来创建所需的结果。要计算每个键的总值,请使用inject方法对每个数组的所有第二个值求和
[[60, 3], [60, 3], [60, 2], [60, 1]].inject(0) {|sum, x| sum + x[1]} #value is 9
答案 1 :(得分:8)
您可以使用Enumerable#each_with_object
使用任意对象迭代每个元素的给定块 给定,并返回最初给定的对象。
items.each_with_object(Hash.new(0)) {|a, h| h[a[0]] += a[1]}.to_a
# => [[60, 9], [276, 8], [48, 6], [207, 5], [46, 3], [280, 2],
# [112, 2], [278, 1], [279, 1]]
来自Stefen的评论
传递给块的数组可以像这样分解
items.each_with_object(Hash.new(0)) {|(k,v), h| h[k] += v}.to_a
答案 2 :(得分:5)
无需对此数据结构进行分组,映射和注入。
Iterator<String> itr = something.iterator();
while (itr.hasNext()){
String x = itr.next();
itr.remove();
somethingElse.add(x);
}
答案 3 :(得分:3)
只是为了获得乐趣,并使用该语言进行游戏:
items.inject([]) { |arr, el| arr[el[0]] = [el[0], (arr[el[0]] || [_, 0])[1] + el[1]]; arr }.compact
这可能更神秘吗?
items.inject([]) { |arr, el|
arr[el[0]] = [el[0], (arr[el[0]] || [_, 0])[1] + el[1]]
arr
}.compact
#inject
方法以空数组开头,并在遍历items
时添加元素。 el
中的每个元素items
都放在arr
的索引处。因此,第一个元素[60, 3]
将被放置在索引60(很多个洞)作为[60, 3]
。
请注意arr
中每个条目的表单:[el[0], (arr[el[0]] || [_, 0])[1] + el[1]]
。这表示第一个元素是公共值,第二个元素加起来,初始化为0。
此解决方案创建了一个包含大量漏洞的数组。 compact
方法删除所有漏洞。
我不推荐这个解决方案,除非是使用该语言练习。
为了获得一些乐趣,我输入了一些答案,所以有时间(不公平和非科学)的比较:
require 'benchmark'
items = [[60, 3], [60, 3], [276, 2], [276, 2], [48, 2], [207, 2], [46, 2],
[60, 2], [280, 2], [207, 1], [48, 1], [112, 1], [60, 1], [207, 1], [112, 1],
[276, 1], [48, 1], [276, 1], [48, 1], [276, 1], [276, 1], [278, 1], [46, 1],
[48, 1], [279, 1], [207, 1]]
Benchmark.bmbm do |x|
x.report(:long) { items.group_by {|i| i[0]}.map{|key, value| [key,value.inject(0){|sum, x| sum + x[1]}]} }
x.report(:randym) { items.reduce(Hash.new { |hash, key| hash[key] = 0 }) { |memo, item| memo[item[0]] = memo[item[0]] + item[1]; memo }.to_a }
x.report(:eric) { items.inject([]) { |arr, el| arr[el[0]] = [el[0], (arr[el[0]] || [0, 0])[1] + el[1]]; arr }.compact }
end
一些输出:
Rehearsal ------------------------------------------
long 0.000000 0.000000 0.000000 ( 0.000016)
randym 0.000000 0.000000 0.000000 ( 0.000014)
eric 0.000000 0.000000 0.000000 ( 0.000011)
--------------------------------- total: 0.000000sec
user system total real
long 0.000000 0.000000 0.000000 ( 0.000013)
randym 0.000000 0.000000 0.000000 ( 0.000011)
eric 0.000000 0.000000 0.000000 ( 0.000008)
Rehearsal ------------------------------------------
long 0.000000 0.000000 0.000000 ( 0.000024)
randym 0.000000 0.000000 0.000000 ( 0.000014)
eric 0.000000 0.000000 0.000000 ( 0.000011)
--------------------------------- total: 0.000000sec
user system total real
long 0.000000 0.000000 0.000000 ( 0.000013)
randym 0.000000 0.000000 0.000000 ( 0.000011)
eric 0.000000 0.000000 0.000000 ( 0.000014)
我的神秘和不可维护可能是最好还是更糟。 Long和Randym是稳定的。
最后一点,以防万一:减去每个解决方案返回的数组,可以检查我们是否都得到了相同的结果: - )
答案 4 :(得分:3)
包含each_with_object的另一种性能表现。 看起来Santhosh是赢家。
require 'benchmark'
items = [[60, 3], [60, 3], [276, 2], [276, 2], [48, 2], [207, 2], [46, 2],
[60, 2], [280, 2], [207, 1], [48, 1], [112, 1], [60, 1], [207, 1], [112, 1],
[276, 1], [48, 1], [276, 1], [48, 1], [276, 1], [276, 1], [278, 1], [46, 1],
[48, 1], [279, 1], [207, 1]]
20.times { items.concat items }
Benchmark.bmbm do |x|
x.report(:long) { items.group_by {|i| i[0]}.map{|key, value| [key,value.inject(0){|sum, x| sum + x[1]}]} }
x.report(:randym) { items.reduce(Hash.new { |hash, key| hash[key] = 0 }) { |memo, item| memo[item[0]] = memo[item[0]] + item[1]; memo }.to_a }
x.report(:eric) { items.inject([]) { |arr, el| arr[el[0]] = [el[0], (arr[el[0]] || [0, 0])[1] + el[1]]; arr }.compact }
x.report(:santhosh) { (items.each_with_object(Hash.new(0)) {|a, h| h[a[0]] += a[1] }).to_a }
end
Rehearsal --------------------------------------------
long 7.130000 0.740000 7.870000 ( 8.464277)
randym 6.380000 0.530000 6.910000 ( 7.520760)
eric 7.730000 0.680000 8.410000 ( 9.135986)
santhosh 5.530000 0.460000 5.990000 ( 6.518203)
---------------------------------- total: 29.180000sec
user system total real
long 7.000000 0.740000 7.740000 ( 8.349310)
randym 6.260000 0.540000 6.800000 ( 7.426409)
eric 7.630000 0.590000 8.220000 ( 8.882282)
santhosh 5.550000 0.460000 6.010000 ( 6.736294)
Ruby 2.1.2 Mac Book Pro(2013) 3 GHz Intel Core i7 8 GB 1600 MHz DDR3
答案 5 :(得分:3)
items.group_by(&:shift).map{|k,v| [k,v.flatten.inject(:+)]}.to_h
但是在其他人应该理解的实际代码中,我会将其分成两行并使用这种方法:
result = Hash.new(0)
items.each{|key,value| result[key] += value}
答案 6 :(得分:2)
items = [[60, 3], [60, 3], [276, 2], [276, 2], [48, 2], [207, 2], [46, 2],
[60, 2], [280, 2], [207, 1], [48, 1], [112, 1], [60, 1], [207, 1], [112, 1],
[276, 1], [48, 1], [276, 1], [48, 1], [276, 1], [276, 1], [278, 1], [46, 1],
[48, 1], [279, 1], [207, 1]]
hash = Hash.new(0)
items.each do |item|
hash[item[0]] += item[1]
end
hash
{60=>9, 276=>8, 48=>6, 207=>5, 46=>3, 280=>2, 112=>2, 278=>1, 279=>1}
hash.to_a
[[60, 9], [276, 8], [48, 6], [207, 5], [46, 3], [280, 2], [112, 2], [278, 1], [279, 1]]