[GOLF]: partitioning an array

Discussion in 'Ruby' started by Max Muermann, Dec 7, 2006.

  1. Max Muermann

    Max Muermann Guest

    Take an array of objects and partition it into subarrays, based on
    some arbitrary property of the objects. I would use this for example
    for generating a report of purchase orders and grouped by week, month,
    year, approximate value, etc.

    The idea is similar to Array#partition, but where partition only does
    a true/false check, the resulting array should be partitioned by the
    return value of a block so that:

    a = ['a','bc','def','g','hi','jkl','m']
    group(a) {|i| i.size} #=> [["a", "g", "m"], ["bc", "hi"], ["def", "jkl"]]


    My best effort so far is this:

    def group array, &block
    h = {}
    array.each do |e|
    (h[yield(e)]||=[])<<e
    end
    h.to_a.map {|e| e[1] }
    end

    For some reason, I cannot bring myself to like this. I have the
    nagging feeling that there is a more elegant way...

    Cheers,
    Max
     
    Max Muermann, Dec 7, 2006
    #1
    1. Advertising

  2. Max Muermann

    Guest

    On Thu, 7 Dec 2006, Max Muermann wrote:

    > Take an array of objects and partition it into subarrays, based on
    > some arbitrary property of the objects. I would use this for example
    > for generating a report of purchase orders and grouped by week, month,
    > year, approximate value, etc.
    >
    > The idea is similar to Array#partition, but where partition only does
    > a true/false check, the resulting array should be partitioned by the
    > return value of a block so that:
    >
    > a = ['a','bc','def','g','hi','jkl','m']
    > group(a) {|i| i.size} #=> [["a", "g", "m"], ["bc", "hi"], ["def", "jkl"]]
    >
    >
    > My best effort so far is this:
    >
    > def group array, &block
    > h = {}
    > array.each do |e|
    > (h[yield(e)]||=[])<<e
    > end
    > h.to_a.map {|e| e[1] }
    > end
    >
    > For some reason, I cannot bring myself to like this. I have the
    > nagging feeling that there is a more elegant way...
    >
    > Cheers,
    > Max


    it's not a good golf solution, but here's a slightly differnet approach:

    harp:~ > cat a.rb
    module Enumerable
    def group_by &b
    h = Hash.new{|h,k| h[k] = []}
    each{|x| h[x.instance_eval(&b)] << x}
    h.values
    end
    end

    a = %w[ a bc def g hi jkl m ]
    p a.group_by{ size }


    h = { 'k' => 'v', 'K' => 'V', 'a' => 'b', 'A' => 'b' }
    p h.group_by{ first.downcase }


    harp:~ > ruby a.rb
    [["a", "g", "m"], ["bc", "hi"], ["def", "jkl"]]
    [[["K", "V"], ["k", "v"]], [["A", "b"], ["a", "b"]]]


    regards.



    -a
    --
    if you want others to be happy, practice compassion.
    if you want to be happy, practice compassion. -- the dalai lama
     
    , Dec 7, 2006
    #2
    1. Advertising

  3. On 07.12.2006 09:46, Ross Bamford wrote:
    > On Thu, 07 Dec 2006 03:46:37 -0000, Max Muermann <> wrote:
    >
    >> Take an array of objects and partition it into subarrays, based on
    >> some arbitrary property of the objects. I would use this for example
    >> for generating a report of purchase orders and grouped by week, month,
    >> year, approximate value, etc.
    >>
    >> The idea is similar to Array#partition, but where partition only does
    >> a true/false check, the resulting array should be partitioned by the
    >> return value of a block so that:
    >>
    >> a = ['a','bc','def','g','hi','jkl','m']
    >> group(a) {|i| i.size} #=> [["a", "g", "m"], ["bc", "hi"], ["def", "jkl"]]
    >>
    >>
    >> My best effort so far is this:
    >>
    >> def group array, &block
    >> h = {}
    >> array.each do |e|
    >> (h[yield(e)]||=[])<<e
    >> end
    >> h.to_a.map {|e| e[1] }


    The last line is definitively superfluous in the light of Hash#values.

    >> end
    >>
    >> For some reason, I cannot bring myself to like this. I have the
    >> nagging feeling that there is a more elegant way...

    >
    > Maybe:
    >
    > a = ['a','bc','def','g','hi','jkl','m']
    > # => ["a", "bc", "def", "g", "hi", "jkl", "m"]
    >
    > a.inject([]){|dst,e|(dst[e.length-1]||=[])<<e;dst}
    > # => [["a", "g", "m"], ["bc", "hi"], ["def", "jkl"]]


    But:

    >> %w{a bbb}.inject([]){|dst,e|(dst[e.length-1]||=[])<<e;dst}

    => [["a"], nil, ["bbb"]]

    I did

    >> a = ['a','bc','def','g','hi','jkl','m']

    => ["a", "bc", "def", "g", "hi", "jkl", "m"]
    >> a.inject(Hash.new {|h,k| h[k]=[]}) {|r,x| r[x.size] << x; r}.values

    => [["a", "g", "m"], ["bc", "hi"], ["def", "jkl"]]

    >> %w{a bbb}.inject(Hash.new {|h,k| h[k]=[]}) {|r,x| r[x.size] << x;

    r}.values
    => [["a"], ["bbb"]]

    Whether that's nicer - I don't know.

    Kind regards

    robert
     
    Robert Klemme, Dec 7, 2006
    #3
  4. On 12/7/06, Robert Klemme <> wrote:
    > Hash.new {|h,k| h[k]=[]}


    This is common enough that it deserves to be its own constructor, imo
    - Hash.multi perhaps

    martin
     
    Martin DeMello, Dec 7, 2006
    #4
  5. Max Muermann

    Dave Burt Guest

    Martin DeMello wrote:
    > On 12/7/06, Robert Klemme <> wrote:
    >> Hash.new {|h,k| h[k]=[]}

    >
    > This is common enough that it deserves to be its own constructor, imo
    > - Hash.multi perhaps


    Would you want one of these, too?

    class Hash
    def self.new_nested
    f = proc {|h, k| h[k] = new(&f) }
    new(&f)
    end
    end

    Cheers,
    Dave
     
    Dave Burt, Dec 7, 2006
    #5
  6. Max Muermann

    Guest

    On Thu, 7 Dec 2006, Martin DeMello wrote:

    > On 12/7/06, Robert Klemme <> wrote:
    >> Hash.new {|h,k| h[k]=[]}

    >
    > This is common enough that it deserves to be its own constructor, imo
    > - Hash.multi perhaps


    my own lib has

    def Hash.list list_class = Array, *a, &b
    Hash.new {|h,k| h[k] = list_class.new(*a, &b)}
    end


    -a
    --
    if you want others to be happy, practice compassion.
    if you want to be happy, practice compassion. -- the dalai lama
     
    , Dec 7, 2006
    #6
  7. Max Muermann

    Trans Guest

    wrote:
    > On Thu, 7 Dec 2006, Martin DeMello wrote:
    >
    > > On 12/7/06, Robert Klemme <> wrote:
    > >> Hash.new {|h,k| h[k]=[]}

    > >
    > > This is common enough that it deserves to be its own constructor, imo
    > > - Hash.multi perhaps

    >
    > my own lib has
    >
    > def Hash.list list_class = Array, *a, &b
    > Hash.new {|h,k| h[k] = list_class.new(*a, &b)}
    > end


    def Hash.new_by(o='[]')
    Hash.new {|h,k| h[k] = eval o}
    end

    Hash.new_by '[]'

    T.
     
    Trans, Dec 7, 2006
    #7
    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. BobRoyAce

    Application "partitioning"

    BobRoyAce, Jan 24, 2005, in forum: ASP .Net
    Replies:
    2
    Views:
    355
    Suhaib Khan
    Jan 24, 2005
  2. Darrel

    Folder 'partitioning'

    Darrel, Apr 13, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    376
    Lau Lei Cheong
    Apr 13, 2006
  3. GianGuz
    Replies:
    4
    Views:
    391
    Jonathan Mcdougall
    Dec 20, 2004
  4. set partitioning

    , May 1, 2006, in forum: Python
    Replies:
    9
    Views:
    488
    Boris Borcic
    May 2, 2006
  5. Peter Szinek

    Partitioning with Set.divide

    Peter Szinek, Apr 29, 2007, in forum: Ruby
    Replies:
    6
    Views:
    134
    Robert Klemme
    Apr 30, 2007
Loading...

Share This Page