Array#group_by

I posted this on the Rails list, but then I realised it would make more
sense
over here:


Just thought I’d share a function which has been really useful to me,
for 2
reasons

  1. It could easily help someone else
  2. People might be able to make it work better or point out where it’s
    not
    optimal

class Array

Groups elements of an array based on a user-defined condition

Each element from this array is passed to the block, and the

returned value

determines the key under which it will be stored in the output hash

If no block is given then the array indices will be used as the hash

keys
def group_by
hsh = {}
self.dup.each_with_index do |element, i|
if block_given?
key = yield element
else
key = i
end
hsh[key] ||= []
hsh[key] << element
end
hsh
end
end

On Wed, Nov 29, 2006 at 10:55:37PM +0900, Gareth A. wrote:
} I posted this on the Rails list, but then I realised it would make
more sense
} over here:
}
} -------
}
} Just thought I’d share a function which has been really useful to me,
for 2
} reasons
}
} 1) It could easily help someone else
} 2) People might be able to make it work better or point out where it’s
not
} optimal

See
http://redcorundum.blogspot.com/2006/06/enumerablebucketby-and-uniqby-and.html
for a post of mine from June that covers that, and more.

–Greg

On Thu, 30 Nov 2006, Bruno M. wrote:

  1. It could easily help someone else
    keys
    end

http://facets.rubyforge.org/api/core/classes/Enumerable.html#M000526

i’m unlear how this adds to inject:

harp:~ > cat a.rb
words = %w( foo bar foobar )

grouped = words.inject Hash.new{|h,k| h[k] = []} do |h,k|
h[k[0,1]] << k; h
end

p grouped

harp:~ > ruby a.rb
{“b”=>[“bar”], “f”=>[“foo”, “foobar”]}

which you can one-line if you wish:

harp:~ > cat a.rb
words = %w( foo bar foobar )
p words.inject({}){|h,k| (h[k[0,1]] ||= []) << k; h}

harp:~ > ruby a.rb
{“b”=>[“bar”], “f”=>[“foo”, “foobar”]}

regards.

-a

Gareth A. a écrit :

optimal
self.dup.each_with_index do |element, i|
end
Hi,

thanks for the tip. I have q question with do you use a “.dup” on the
line self.dup.each_with_index do |element, i| ? Facets has a similar
function (partition_by), but don’t use a “.dup” before iterating:

http://facets.rubyforge.org/api/core/classes/Enumerable.html#M000526

If you don’t care about duplicates, just use Set#classify.

Louis J Scoras wrote:

If you don’t care about duplicates, just use Set#classify.

Why isn’t there an Array#classify, which would return a hash of arrays,
preserving duplicates?

On 11/29/06, Joel VanderWerf [email protected] wrote:

Why isn’t there an Array#classify, which would return a hash of arrays,
preserving duplicates?

Beats me =) I’m not arguing against such a method; just pointing out
that there’s already something that might get the job done. A lot of
times people use arrays to represent sets without realizing it.

On Wed, 2006-11-29 at 22:55 +0900, Gareth A. wrote:

  if block_given?
    key = yield element
  else
    key = i
  end
  hsh[key] ||= []
  hsh[key] << element
end
hsh

end
end

Here’s an improved version:

module Enumerable
def group_by
hsh = Hash.new{|hsh, key| hsh[key] = [] }
if block_given?
each{|obj| hsh[yield(obj)].push(obj) }
else
each_with_index{|obj, i| hsh[i].push(obj) }
end
hsh
end
end

Cheers,
Daniel S.

Louis J Scoras wrote:

On 11/29/06, Joel VanderWerf [email protected] wrote:

Why isn’t there an Array#classify, which would return a hash of arrays,
preserving duplicates?

Beats me =) I’m not arguing against such a method; just pointing out
that there’s already something that might get the job done. A lot of
times people use arrays to represent sets without realizing it.

I wasn’t arguing either. I had forgotten about the useful Set#classify,
and thought why not have one for Array too? I can’t see any theoretical
reason not to.