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 <eustaquiorangel@gmail.com>
To: ruby-talk ML <ruby-talk@ruby-lang.org>
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.

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

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

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]

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

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

=> [55, 1]

['dog','dog','cat','bird',5,5,42].mode

=> [5, "dog"]

-Rob

···

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

----- Original Message ----
From: Eustáquio 'TaQ' Rangel <eustaquiorangel@gmail.com>
To: ruby-talk ML <ruby-talk@ruby-lang.org>
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.

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

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

···

On Tue, Sep 30, 2008 at 6:02 PM, Rob Biedenharn <Rob@agileconsultingllc.com> wrote:

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

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

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

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]

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

> [3,1,1,55,55].mode
=> [55, 1]
> ['dog','dog','cat','bird',5,5,42].mode
=> [5, "dog"]

-Rob