[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Grouping array elements while preserving order?

Matt Constantine

9/20/2008 9:47:00 PM

Hi all,

I've run into a number of situations where I need to group an array
while preserving order. For example, grouping the results of a database
query without affecting their order or introducing extraneous logic in a
view.

I would like to know if there are any obvious problems or improvements
to this solution:

class Array
def partition_by(&b)
out=[]
self.inject([]) {|acc,e|
last = acc.pop
value = b.call(e)
out << {value=>[]} if last != value
out.last[value] << e
acc << value
}
out
end
end

So if I partition an array by element length, for example (contrived, I
know):
animals = %w(dog dog cat chicken chicken dog)
animals.partition_by{|x| x.length}

I get:
[{3=>["dog", "dog", "cat"]}, {7=>["chicken", "chicken"]}, {3=>["dog"]}]

Any thoughts or suggestions?

- Matt
--
Posted via http://www.ruby-....

2 Answers

William James

9/21/2008 1:22:00 AM

0

On Sep 20, 4:47 pm, Matt Constantine <desig...@gmail.com> wrote:
> Hi all,
>
> I've run into a number of situations where I need to group an array
> while preserving order. For example, grouping the results of a database
> query without affecting their order or introducing extraneous logic in a
> view.
>
> I would like to know if there are any obvious problems or improvements
> to this solution:
>
> class Array
> def partition_by(&b)
> out=[]
> self.inject([]) {|acc,e|
> last = acc.pop
> value = b.call(e)
> out << {value=>[]} if last != value
> out.last[value] << e
> acc << value
> }
> out
> end
> end
>
> So if I partition an array by element length, for example (contrived, I
> know):
> animals = %w(dog dog cat chicken chicken dog)
> animals.partition_by{|x| x.length}
>
> I get:
> [{3=>["dog", "dog", "cat"]}, {7=>["chicken", "chicken"]}, {3=>["dog"]}]

Without hashes:

class Array
def group_by
key = nil
inject([]){|result,x|
k = yield x
if key == k and result != []
result[-1] << x
next result
end
key = k
result << [x]
}
end
end

Robert Klemme

9/22/2008 5:27:00 AM

0

On 21.09.2008 03:22, William James wrote:
> On Sep 20, 4:47 pm, Matt Constantine <desig...@gmail.com> wrote:
>> Hi all,
>>
>> I've run into a number of situations where I need to group an array
>> while preserving order. For example, grouping the results of a database
>> query without affecting their order or introducing extraneous logic in a
>> view.
>>
>> I would like to know if there are any obvious problems or improvements
>> to this solution:
>>
>> class Array
>> def partition_by(&b)
>> out=[]
>> self.inject([]) {|acc,e|
>> last = acc.pop
>> value = b.call(e)
>> out << {value=>[]} if last != value
>> out.last[value] << e
>> acc << value
>> }
>> out
>> end
>> end
>>
>> So if I partition an array by element length, for example (contrived, I
>> know):
>> animals = %w(dog dog cat chicken chicken dog)
>> animals.partition_by{|x| x.length}
>>
>> I get:
>> [{3=>["dog", "dog", "cat"]}, {7=>["chicken", "chicken"]}, {3=>["dog"]}]
>
> Without hashes:
>
> class Array
> def group_by
> key = nil
> inject([]){|result,x|
> k = yield x
> if key == k and result != []
> result[-1] << x
> next result
> end
> key = k
> result << [x]
> }
> end
> end

You're loosing keys there. Maybe rather

module Enumerable
def group_by_ordered
inject([]) do |agg, v|
k = yield v
if agg.empty? || k != agg.last.first
agg << [k, [v]]
else
agg.last.last << v
end
agg
end
end
end

irb(main):014:0> animals = %w(dog dog cat chicken chicken dog)
=> ["dog", "dog", "cat", "chicken", "chicken", "dog"]
irb(main):015:0> animals.group_by_ordered {|x| x.length}
=> [[3, ["dog", "dog", "cat"]], [7, ["chicken", "chicken"]], [3, ["dog"]]]
irb(main):016:0>

Cheers

robert