group in the array

Discussion in 'Ruby' started by Kolya17 Kolya17, Jan 6, 2010.

  1. 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.
    --
    Posted via http://www.ruby-forum.com/.
     
    Kolya17 Kolya17, Jan 6, 2010
    #1
    1. Advertising

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

    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

    --
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
     
    Robert Klemme, Jan 6, 2010
    #2
    1. Advertising

  3. Kolya17 Kolya17

    Ralf Mueller Guest

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

    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 Mueller, Jan 6, 2010
    #3
  4. Kolya17 Kolya17

    Ralf Mueller Guest

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

    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
     
    Ralf Mueller, Jan 6, 2010
    #4
  5. Kolya17 Kolya17

    Dektor Mari Guest

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



    Many thanks, Ralf!
    It works!
    --
    Posted via http://www.ruby-forum.com/.
     
    Dektor Mari, Jan 6, 2010
    #5
  6. Kolya17 Kolya17

    Jeff Peng Guest

    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 Peng, Jan 6, 2010
    #6
  7. Kolya17 Kolya17

    Dektor Mari Guest

    Jeff Peng wrote:
    > You could use a hash for translating that.


    Also works.
    Thank you!
    --
    Posted via http://www.ruby-forum.com/.
     
    Dektor Mari, Jan 6, 2010
    #7
  8. Kolya17 Kolya17

    Ralf Mueller Guest

    Robert Klemme wrote:
    > 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)

    regards
    ralf
     
    Ralf Mueller, Jan 6, 2010
    #8
  9. On 01/06/2010 03:56 PM, Ralf Mueller wrote:
    > Robert Klemme wrote:
    >> 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

    Cheers

    robert


    --
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
     
    Robert Klemme, Jan 6, 2010
    #9
  10. Kolya17 Kolya17

    Ruby Newbee Guest

    Ruby Newbee, Jan 7, 2010
    #10
  11. Kolya17 Kolya17

    Ruby Newbee Guest

    On Thu, Jan 7, 2010 at 11:19 AM, Ruby Newbee <> wrote:
    > On Wed, Jan 6, 2010 at 11:20 PM, Robert Klemme
    > <> wrote:
    >
    >>
    >> inject
    >> http://ruby-doc.org/core-1.8.7/classes/Enumerable.html#M001147
    >>

    >
    > 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.
     
    Ruby Newbee, Jan 7, 2010
    #11
  12. Kolya17 Kolya17

    Ralf Mueller Guest

    Robert Klemme wrote:
    > On 01/06/2010 03:56 PM, Ralf Mueller wrote:
    >> Robert Klemme wrote:
    >>> 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
     
    Ralf Mueller, Jan 7, 2010
    #12
  13. On 01/07/2010 05:00 AM, Ruby Newbee wrote:
    > On Thu, Jan 7, 2010 at 11:19 AM, Ruby Newbee <> wrote:
    >> On Wed, Jan 6, 2010 at 11:20 PM, Robert Klemme
    >> <> wrote:
    >>
    >>> inject
    >>> http://ruby-doc.org/core-1.8.7/classes/Enumerable.html#M001147


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

    --
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
     
    Robert Klemme, Jan 7, 2010
    #13
  14. On Thu, Jan 7, 2010 at 4:50 AM, Robert Klemme
    <> wrote:
    > On 01/07/2010 05:00 AM, Ruby Newbee wrote:
    >>
    >> On Thu, Jan 7, 2010 at 11:19 AM, Ruby Newbee <> wrot=

    e:
    >>>
    >>> On Wed, Jan 6, 2010 at 11:20 PM, Robert Klemme
    >>> <> wrote:
    >>>
    >>>> inject
    >>>> http://ruby-doc.org/core-1.8.7/classes/Enumerable.html#M001147

    >
    >>> 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 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=
     
    Rick DeNatale, Jan 7, 2010
    #14
  15. 2010/1/7 Rick DeNatale <>:
    > On Thu, Jan 7, 2010 at 4:50 AM, Robert Klemme
    > <> wrote:
    >> 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/
     
    Robert Klemme, Jan 9, 2010
    #15
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Akaketwa
    Replies:
    1
    Views:
    5,061
    impaler
    Sep 22, 2006
  2. Replies:
    0
    Views:
    572
  3. christopher taylor
    Replies:
    0
    Views:
    440
    christopher taylor
    Sep 17, 2008
  4. cpld-fpga-asic
    Replies:
    13
    Views:
    1,221
    rickman
    Jul 6, 2009
  5. Dag Sunde
    Replies:
    0
    Views:
    137
    Dag Sunde
    Nov 18, 2005
Loading...

Share This Page