group in the array

  • Thread starter Kolya17 Kolya17
  • Start date
K

Kolya17 Kolya17

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.
 
R

Robert Klemme

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.

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
 
R

Ralf Mueller

Kolya17 said:
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.
Hi,
I guess sort_by from the Enumerable Module fits your needs:
http://www.ruby-doc.org/core/classes/Enumerable.html#M003120

regards
ralf
 
R

Ralf Mueller

Kolya17 said:
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.
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
 
J

Jeff Peng

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
 
R

Ralf Mueller

Robert said:
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.

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
 
R

Robert Klemme

Robert said:
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.
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
http://ruby-doc.org/core-1.8.7/classes/Enumerable.html#M001150

inject
http://ruby-doc.org/core-1.8.7/classes/Enumerable.html#M001147

Cheers

robert
 
R

Ruby Newbee

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?

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.
 
R

Ralf Mueller

Robert said:
Robert said:
On 01/06/2010 09:45 AM, Kolya17 Kolya17 wrote:
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.
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
http://ruby-doc.org/core-1.8.7/classes/Enumerable.html#M001150

inject
http://ruby-doc.org/core-1.8.7/classes/Enumerable.html#M001147
thanks robert!
I've always used ruby-doc.org/core 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
 
R

Robert Klemme

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
 
R

Rick DeNatale

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 abo= ut
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]
=3D> nil
irb(main):002:0> (1..5).inject(0) {|*a| p a; nil}
[0, 1]
[nil, 2]
[nil, 3]
[nil, 4]
[nil, 5]
=3D> nil

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

Robert Klemme

2010/1/7 Rick DeNatale said:
On 01/07/2010 05:00 AM, Ruby Newbee wrote:
I don't know Python's reduce but a few things are probably noteworthy ab= out
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]
=3D> nil
irb(main):002:0> (1..5).inject(0) {|*a| p a; nil}
[0, 1]
[nil, 2]
[nil, 3]
[nil, 4]
[nil, 5]
=3D> nil

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

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

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

irb(main):005:0> [].inject {|sum,x| sum + x}
=3D> 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.
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]
=A0=3D> 15
ruby-1.8.7-p174 > (1..5).inject {|sum,x| p [sum, x]; sum + x}
[1, 2]
[3, 3]
[6, 4]
[10, 5]
=A0=3D> 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. =A0I 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.

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)

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,054
Latest member
LucyCarper

Latest Threads

Top