Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Ruby (http://www.velocityreviews.com/forums/f66-ruby.html)
-   -   [GOLF]: partitioning an array (http://www.velocityreviews.com/forums/t836148-golf-partitioning-an-array.html)

Max Muermann 12-07-2006 03:46 AM

[GOLF]: partitioning an array
 
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


ara.t.howard@noaa.gov 12-07-2006 04:25 AM

Re: [GOLF]: partitioning an array
 
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


Robert Klemme 12-07-2006 09:01 AM

Re: [GOLF]: partitioning an array
 
On 07.12.2006 09:46, Ross Bamford wrote:
> On Thu, 07 Dec 2006 03:46:37 -0000, Max Muermann <ruby@muermann.org> 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

Martin DeMello 12-07-2006 09:26 AM

Re: [GOLF]: partitioning an array
 
On 12/7/06, Robert Klemme <shortcutter@googlemail.com> wrote:
> Hash.new {|h,k| h[k]=[]}


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

martin


Dave Burt 12-07-2006 02:19 PM

Re: [GOLF]: partitioning an array
 
Martin DeMello wrote:
> On 12/7/06, Robert Klemme <shortcutter@googlemail.com> 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

ara.t.howard@noaa.gov 12-07-2006 02:44 PM

Re: [GOLF]: partitioning an array
 
On Thu, 7 Dec 2006, Martin DeMello wrote:

> On 12/7/06, Robert Klemme <shortcutter@googlemail.com> 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


Trans 12-07-2006 09:03 PM

Re: [GOLF]: partitioning an array
 

ara.t.howard@noaa.gov wrote:
> On Thu, 7 Dec 2006, Martin DeMello wrote:
>
> > On 12/7/06, Robert Klemme <shortcutter@googlemail.com> 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.




All times are GMT. The time now is 03:37 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.