Frequency of objects in an array using Ruby

If I had a list of balls, each of which has a color property. how can I get a list of balls with the most frequent color.

[m1,m2,m3,m4] 

eg,

  m1.color = blue m2.color = blue m3.color = red m4.color = blue 

[m1,m2,m4] - list of balls with the most frequent color

My approach should do:

 [m1,m2,m3,m4].group_by{|ball| ball.color}.each do |samecolor| my_items = samecolor.count end 

where count is defined as

 class Array def count k =Hash.new(0) self.each{|x|k[x]+=1} k end end 

my_items will be a hash of frequencies for the same color group. My implementation may be a mistake, and I feel that there must be a better and more reasonable way. any ideas please?

+4
source share
7 answers

Your code is not bad, but it is inefficient. If I were you, I would look for a solution that repeats through your array only once, for example:

 balls = [m1, m2, m3, m4] most_idx = nil groups = balls.inject({}) do |hsh, ball| hsh[ball.color] = [] if hsh[ball.color].nil? hsh[ball.color] << ball most_idx = ball.color if hsh[most_idx].nil? || hsh[ball.color].size > hsh[most_idx].size hsh end groups[most_idx] # => [m1,m2,m4] 

This is basically the same as group_by , but at the same time it counts the groups and keeps a record of which group is the largest ( most_idx ).

+2
source

You found group_by but missed max_by

 max_color, max_balls = [m1,m2,m3,m4].group_by {|b| b.color}.max_by {|color, balls| balls.length} 
+5
source

What about:

color,balls = [m1,m2,m3,m4].group_by { |b| b.color }.max_by(&:size)

+2
source

This is how I do it. The main idea uses injection to accumulate values ​​in a hash and comes from "12 - building a histogram" in "The Ruby Cookbook".

  #! / usr / bin / env ruby

 class M
   attr_reader: color
   def initialize (c)
     @color = c
   end
 end

 m1 = M.new ('blue')
 m2 = M.new ('blue')
 m3 = M.new ('red')
 m4 = M.new ('blue')

 hash = [m1.color, m2.color, m3.color, m4.color] .inject (Hash.new (0)) {| h, x |  h [x] + = 1;  h} # => {"blue" => 3, "red" => 1}
 hash = [m1, m2, m3, m4] .inject (Hash.new (0)) {| h, x |  h [x.color] + = 1;  h} # => {"blue" => 3, "red" => 1}

There are two different ways to do this, depending on how much knowledge you want inject () to know about your objects.

+2
source

it turns out the reverse sorted list of balls in frequency

 balls.group_by { |b| b.color } .map { |k, v| [k, v.size] } .sort_by { |k, count| -count} 
+2
source

two parts, I will use an example of your strange balls, but will also include my own example of rails

 ary = [m1,m2,m3,m4] colors = ary.each.map(&:color) #or ary.each.map {|t| t.color } Hash[colors.group_by(&:w).map {|w, ws| [w, ws.length] }] #=> {"blue" => 3, "red" => 1 } 

my example is ActiveRecord

 stocks = Sp500Stock.all Hash[stocks.group_by(&:sector).map {|w, s| [w, s.length] }].sort_by { |k,v| v } #=> {"Health Care" => 36, etc] 
+2
source
 myhash = {} mylist.each do |ball| if myhash[ball.color] myhash[ball.color] += 1 else myhash[ball.color] = 1 end end puts myhash.sort{|a,b| b[1] <=> a[1]} 
0
source

Source: https://habr.com/ru/post/1304360/


All Articles