Re: Mode method for Array

Hi,

I wrote 2 ways. I don’t know if either way is good or not. Any
feedback is welcome.

The first way makes a hash of the array, with the unique values in the
array as the keys, and the number of times the keys occur as the values.
Then I create a new hash out of that first hash with the frequencies as
the keys of the hash and the elements that had that frequency as the
values. Then I pick out the value of the highest key.

The second way creates that frequency hash, then iterates over the hash
and creates an array with the elements that have the highest frequency.

class Array
def hash_of_frequency
h = Hash.new(0)
each_with_index do |e, i|
e = e.to_f if e != nil
h[e] = h[e] += 1
end
h
end

def get_mode
h = hash_of_frequency.frequency_in_key
h[h.keys.max].sort
end
end

class Hash
def frequency_in_key
h = Hash.new { |k, v| k[v] = [] }
each { |k, v| h[v] << k if k != nil }
h
end

def get_mode
a = []
max_value = values.max
each { |k, v| a << k if v == max_value }
a
end
end

[3, 1, 1, 55, 55].hash_of_frequency.get_mode.inspect ## returns [1.0,
55.0]
[3, 1, 1, 55, 55].get_mode.inspect ## returns[1.0, 55.0]

----- Original Message ----
From: Eustáquio ‘TaQ’ Rangel [email protected]
To: ruby-talk ML [email protected]
Sent: Tuesday, September 30, 2008 6:14:35 PM
Subject: Re: Mode method for Array

I’d like to write a get_mode method for the Array class. The method would return an array of the most frequently occurring element or elements.
So [3, 1, 1, 55, 55].get_mode would return [1, 55].
I have a way to do this but I don’t know if it’s the best way. I was wondering if anyone had any suggestions?

What is your way? Maybe we can have some idea of what parameters you are
using
to the the most frequently elements. Using something like

irb(main):001:0> [3,1,1,55,55].inject(Hash.new(0)){|memo,item|
memo[item] += 1;
memo}.sort_by {|e| e[1]}.reverse
=> [[55, 2], [1, 2], [3, 1]]

can return you some elements ordered by frequency.

On Sep 30, 2008, at 6:30 PM, Glenn wrote:

key.
h[e] = h[e] += 1
end
h
end

You never use i, so just use each (and loose the second block parameter)

h[e] = h[e] += 1 ???
Did you mean just: h[e] += 1

h

[3, 1, 1, 55, 55].hash_of_frequency.get_mode.inspect ## returns
[1.0, 55.0]
[3, 1, 1, 55, 55].get_mode.inspect ## returns[1.0, 55.0]

If you don’t bother with the .to_f on the elements, you could define
this over ANY Enumerable with a variation on what TaQ posted;
something like:

module Enumerable
def mode
alist = inject(Hash.new(0)) {|h,e| h[e]+=1;h}.sort_by {|(e,c)| -c}
alist.select {|(e,c)| c == alist[0][1]}.map{|(e,c)| e}
end
end

irb> [3,1,1,55,55].mode
=> [55, 1]
irb> [‘dog’,‘dog’,‘cat’,‘bird’,5,5,42].mode
=> [5, “dog”]

-Rob

I have a way to do this but I don’t know if it’s the best way. I

can return you some elements ordered by frequency.

Rob B. http://agileconsultingllc.com
[email protected]

On Tue, Sep 30, 2008 at 6:02 PM, Rob B.
[email protected] wrote:

keys of the hash and the elements that had that frequency as the values.
h[e] = h[e] += 1
h = hash_of_frequency.frequency_in_key

55.0]
end

irb> [3,1,1,55,55].mode
=> [55, 1]
irb> [‘dog’,‘dog’,‘cat’,‘bird’,5,5,42].mode
=> [5, “dog”]

-Rob

I was thinking similarly…

module Enumerable
def mode
h, max = inject(Hash.new(0)) {|h, i| h[i] += 1; h}, h.values.max
h.select {|k, v| v == max}.transpose.first
end
end

p [3, 1, 55, 1, 55].mode

=> [55, 1]

Sort afterward if you want.

Todd