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?
On Sep 20, 4:47 pm, Matt C. [email protected] wrote:
class Array
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
On 21.09.2008 03:22, William J. wrote:
out
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