Group in the array

Hi!

I have a two-dimensional array Farr.

Farr.each{ |i| print i}

output:
[“200912-829”, 9]
[“200912-893”, 3]
[“200912-893”, 5]
[“200912-829”, 1]
[“200911-818”, 6]
[“200911-893”, 1]
[“200911-827”, 2]

I’m trying to get another two-dimensional array, which would be the
grouping of the first elements.
In SQL it would be so:

select String, sum(Number)
from Farr
group by String

and the resulting array would:
[“200912-829”, 10]
[“200912-893”, 8]
[“200911-818”, 6]
[“200911-893”, 1]
[“200911-827”, 2]

Help please.
I apologize for spelling, English is not my native.

Kolya17 Kolya17 wrote:

[“200912-829”, 1]
group by String

Hi,
I guess sort_by from the Enumerable Module fits your needs:
http://www.ruby-doc.org/core/classes/Enumerable.html#M003120

regards
ralf

Ralf M. wrote:

sort_by might be to simple for you, because of the sum. I tried this:

Many thanks, Ralf!
It works!

Kolya17 Kolya17 wrote:

[“200912-829”, 1]
group by String

and the resulting array would:
[“200912-829”, 10]
[“200912-893”, 8]
[“200911-818”, 6]
[“200911-893”, 1]
[“200911-827”, 2]

Help please.

Hi again,
sort_by might be to simple for you, because of the sum. I tried this:

irb(main):039:0> a = [[“200912-829”, 10],[“200912-893”,
8],[“200911-818”, 6],[“200912-893”, 5]]
=> [[“200912-829”, 10], [“200912-893”, 8], [“200911-818”, 6],
[“200912-893”, 5]]
irb(main):040:0> aH = {}
=> {}
irb(main):041:0> a.each {|k,v| aH[k] = 0 if aH[k].nil?; aH[k] += v}
=> [[“200912-829”, 10], [“200912-893”, 8], [“200911-818”, 6],
[“200912-893”, 5]]
irb(main):042:0> aH.sort
=> [[“200911-818”, 6], [“200912-829”, 10], [“200912-893”, 13]]

hth
ralf

Kolya17 Kolya17:

I’m trying to get another two-dimensional array, which would be the
grouping of the first elements.
In SQL it would be so:

Hi,

You could use a hash for translating that.

x= [[“200912-829”, 9],[“200912-893”, 3],[“200912-893”, 5],[“200912-829”,
1],[“200911-818”, 6],[“200911-893”, 1],[“200911-827”, 2]]

hash = Hash.new(0)
x.each do |c| hash[c[0]] += c[1] end

new = hash.to_a
p new

Jeff P. wrote:

You could use a hash for translating that.

Also works.
Thank you!

Robert K. wrote:

[“200912-893”, 5]
from Farr
I apologize for spelling, English is not my native.

There is actually Array#group_by since 1.8.7:

arr.group_by {|date,val| date}.each do |date, items|
printf “%-20s %6d\n”, date, items.inject(0) {|sum,x|sum+x}, “\n”
end

Looks good, but I could not find it in the online documentation on
ruby-doc.org? (Array,Enumerable)

regards
ralf

On 01/06/2010 03:56 PM, Ralf M. wrote:

[“200912-893”, 3]
select String, sum(Number)
Help please.
I apologize for spelling, English is not my native.
There is actually Array#group_by since 1.8.7:

arr.group_by {|date,val| date}.each do |date, items|
printf “%-20s %6d\n”, date, items.inject(0) {|sum,x|sum+x}, “\n”
end

Looks good, but I could not find it in the online documentation on
ruby-doc.org? (Array,Enumerable)

That’s weird. I found it immediately:

group_by

inject

Cheers

robert

On 01/06/2010 09:45 AM, Kolya17 Kolya17 wrote:

[“200912-829”, 1]
group by String

and the resulting array would:
[“200912-829”, 10]
[“200912-893”, 8]
[“200911-818”, 6]
[“200911-893”, 1]
[“200911-827”, 2]

Help please.
I apologize for spelling, English is not my native.

There is actually Array#group_by since 1.8.7:

arr.group_by {|date,val| date}.each do |date, items|
printf “%-20s %6d\n”, date, items.inject(0) {|sum,x|sum+x}, “\n”
end

or

arr.inject Hash.new(0) do |gr,(date,val)|
gr[date] += val
gr
end.each do |date, sum|
printf “%-20s %6d\n”, date, sum
end

or more down to earth

grouped = Hash.new(0)

arr.each do |date, val|
grouped[date] += val
end

grouped.each do |date, sum|
printf “%-20s %6d\n”, date, sum
end

Kind regards

robert

On Thu, Jan 7, 2010 at 11:19 AM, Ruby N. [email protected]
wrote:

I have checked the document for inject, but still can’t understand for.
Can you help explain it with general words by a little samples?

Hi again,

Now I checked some other help documents wigh google, and find Ruby’s
inject is similiar to Python’s reduce, which is known by me.
Thanks anyway.

Robert K. wrote:

[“200912-829”, 9]

That’s weird. I found it immediately:

group_by
Module: Enumerable (Ruby 1.8.7)

inject
Module: Enumerable (Ruby 1.8.7)

thanks robert!
I’ve always used RDoc Documentation for getting the latest 1.8 doc.
Didn’t recognized, it belongs to 1.8.6 instead of the more recent
1.8.7…

regards
ralf

On Wed, Jan 6, 2010 at 11:20 PM, Robert K.
[email protected] wrote:

inject
Module: Enumerable (Ruby 1.8.7)

Hi,

I have checked the document for inject, but still can’t understand for.
Can you help explain it with general words by a little samples?

Thanks in advance.

On 01/07/2010 05:00 AM, Ruby N. wrote:

On Thu, Jan 7, 2010 at 11:19 AM, Ruby N. [email protected] wrote:

On Wed, Jan 6, 2010 at 11:20 PM, Robert K.
[email protected] wrote:

inject
Module: Enumerable (Ruby 1.8.7)

I have checked the document for inject, but still can’t understand for.
Can you help explain it with general words by a little samples?

Now I checked some other help documents wigh google, and find Ruby’s
inject is similiar to Python’s reduce, which is known by me.

I don’t know Python’s reduce but a few things are probably noteworthy
about Ruby’s #inject:

It does matter whether you provide an argument or not:

irb(main):001:0> (1…5).inject {|*a| p a; nil}
[1, 2]
[nil, 3]
[nil, 4]
[nil, 5]
=> nil
irb(main):002:0> (1…5).inject(0) {|*a| p a; nil}
[0, 1]
[nil, 2]
[nil, 3]
[nil, 4]
[nil, 5]
=> nil

This means that when summing up you usually want to provide 0 as
argument. For other use cases, e.g. concatenating you probably do not
want to:

irb(main):003:0> (1…5).inject(0) {|sum,x| sum + x}
=> 15
irb(main):004:0> [].inject(0) {|sum,x| sum + x}
=> 0

Whithout you do not get a sum for the empty collection:

irb(main):005:0> [].inject {|sum,x| sum + x}
=> nil

Not providing an argument can be useful as well:

irb(main):008:0> (1…5).inject {|a,b| a.to_s << “,” << b.to_s}
=> “1,2,3,4,5”

(Of course, that’s better done with #join.)

And Ruby’s pattern matching for block arguments makes it easy to process
Hash and other collections that have more than one object per iteration:

irb(main):001:0> h={1=>2,3=>4}
=> {1=>2, 3=>4}
irb(main):002:0> h.inject(0) {|sum, (key, val)| sum + key + val}
=> 10

Kind regards

robert

On Thu, Jan 7, 2010 at 4:50 AM, Robert K.
[email protected] wrote:

I have checked the document for inject, but still can’t understand for.
irb(main):001:0> (1…5).inject {|*a| p a; nil}
[nil, 5]
Whithout you do not get a sum for the empty collection:

irb(main):005:0> [].inject {|sum,x| sum + x}
=> nil

Which you may or may not want.

I’m not sure I see the logic of why you example alone leads to the
recommendation to provide the 0 argument:

ruby-1.8.7-p174 > (1…5).inject(0) {|sum,x| p [sum, x]; sum + x}
[0, 1]
[1, 2]
[3, 3]
[6, 4]
[10, 5]
=> 15
ruby-1.8.7-p174 > (1…5).inject {|sum,x| p [sum, x]; sum + x}
[1, 2]
[3, 3]
[6, 4]
[10, 5]
=> 15

I’ve come to use inject or reduce depending on whether or not I’m
providing the argument, assuming I’m using a version of Ruby which
aliases them. I think that inject without an argument is a bit
mysterious, because that argument is what you are injecting.

I think that most languages which have a form of reduce don’t allow
that argument, as far as I know, it came from Smaltalk whose form of
reduce came from the inject:initialValue into: aBlock method on
collection classes. For an old Smaltalker Ruby’s inject was no
mystery, but using reduce when not supplying the argument makes more
sense to me.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: Rick DeNatale - Developer - IBM | LinkedIn

2010/1/7 Rick DeNatale [email protected]:

On Thu, Jan 7, 2010 at 4:50 AM, Robert K.
[email protected] wrote:

On 01/07/2010 05:00 AM, Ruby N. wrote:

=> nil

Which you may or may not want.
I’d say normally you want 0 for an empty collection because that is
the neutral element for addition. Any code relying on uniform further
processing of the result of summing up the collection will be simpler
if 0 is injected for the sum.

I’m not sure I see the logic of why you example alone leads to the
recommendation to provide the 0 argument:

Because the empty Enumerable is the one where behavior differs.

[6, 4]
reduce came from the inject:initialValue into: aBlock method on
collection classes. For an old Smaltalker Ruby’s inject was no
mystery, but using reduce when not supplying the argument makes more
sense to me.

So you are basically saying that you pick the method name depending on
whether you provide an argument or not. Actually I had forgotten
about #reduce completely. OTOH I use the method rarely nowadays but
when I use it I provide an argument most of the time.

Kind regards

robert

PS: Your posting was somehow cut off on my news server. Does anybody
else experience the same? The cut was after

This means that when summing up you usually want to provide 0 as argument

(~ line 40)