Ruby多维数组 - 删除第一个位置的副本,在第二个位置添加数字

时间:2016-02-03 04:40:40

标签: arrays ruby

对于这个数组:

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]等等。

7 个答案:

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