Ruby Multidimensional Array - Remove duplicate in first position, add number in second position

For this array:

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

I want to combine the totals in the first positions of each subband and add the numbers in the second position together.

For example, you will see the first four sub-arrays: [60, 3], [60, 3], [276, 2], [276, 2]

This will become the following: [60,6], [276,4]etc.

+4
source share
7 answers

try it

items.
  group_by {|i| i[0]}.
  map{|key, value| [key,value.inject(0){|sum, x| sum + x[1]}]}

First, use group_by to create a hash whose keys are the first element of each array. So we have

{
 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
+9

# 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
+8

, .

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

# Provide a default value of 0 for all created entries in the hash.
# This saves us from having to conditionally set undefined entries to 0
# http://docs.ruby-lang.org/en/2.0.0/Hash.html
accumulator = Hash.new(0) # Thanks Eric!

# using reduce lets us perform the grouping and adding in one pass.
# as each  item is passed in, we define a member on our accumulator
# for the first number in the pair, and add the value of the second
# number in the pair to our member.
# http://docs.ruby-lang.org/en/2.0.0/Enumerable.html#method-i-reduce
output = items.reduce(accumulator) do |memo, item|
  memo[item[0]] = memo[item[0]] + item[1]
  memo
end

# Finally, convert the hash to an array
output.to_a

# => [[60, 9], [276, 8], [48, 6], [207, 5], [46, 3], [280, 2], [112, 2], [278, 1], [279, 1]]
+5

, , :

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 .

, : , , , : -)

+3

each_with_object. , - .

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) Intel Core i7 3 8 1600 DDR3

+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}
+3
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]]
+2

Source: https://habr.com/ru/post/1627099/


All Articles