[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

[GOLF]: partitioning an array

Max Muermann

12/7/2006 3:47:00 AM

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

7 Answers

Ara.T.Howard

12/7/2006 4:25:00 AM

0

Ross Bamford

12/7/2006 8:46:00 AM

0

On Thu, 07 Dec 2006 03:46:37 -0000, Max Muermann <ruby@muermann.org> wro=
te:

> 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 =3D ['a','bc','def','g','hi','jkl','m']
> group(a) {|i| i.size} #=3D> [["a", "g", "m"], ["bc", "hi"], ["def", "j=
kl"]]
>
>
> My best effort so far is this:
>
> def group array, &block
> h =3D {}
> array.each do |e|
> (h[yield(e)]||=3D[])<<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...
>

Maybe:

a =3D ['a','bc','def','g','hi','jkl','m']
# =3D> ["a", "bc", "def", "g", "hi", "jkl", "m"]

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



-- =

Ross Bamford - rosco@roscopeco.remove.co.uk

Robert Klemme

12/7/2006 9:01:00 AM

0

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/7/2006 9:27:00 AM

0

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/7/2006 2:19:00 PM

0

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

12/7/2006 2:44:00 PM

0

Trans

12/7/2006 9:04:00 PM

0


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.