Grouping array elements while preserving order?

M

Matt Constantine

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
 
W

William James

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
 
R

Robert Klemme

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top