Grouping array elements while preserving order?

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-forum.com/.

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 <<
    }
  end
end

···

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"]}]

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

···

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 <<
    }
  end
end