частота объектов в массиве с использованием Ruby - PullRequest
4 голосов
/ 17 марта 2010

Если бы у меня был список шаров, каждый из которых имеет свойство цвета. Как я могу получить список шаров с наиболее часто встречающимся цветом.

[m1,m2,m3,m4]

скажем,

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

[m1,m2,m4] - список шаров с наиболее часто встречающимся цветом

Мой подход заключается в следующем:

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

где количество определяется как

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

my_items будет хешем частот для каждой цветовой группы. Моя реализация может быть ошибочной, и я чувствую, что должен быть лучший и более умный способ. есть идеи, пожалуйста?

Ответы [ 7 ]

5 голосов
/ 17 марта 2010

Вы нашли group_by, но пропустили max_by

max_color, max_balls = [m1,m2,m3,m4].group_by {|b| b.color}.max_by {|color, balls| balls.length}
2 голосов
/ 16 декабря 2012

две части, я буду использовать пример ваших странных шаров, но также буду включать в себя мой собственный пример с рельсами

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 }

мой пример 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 голосов
/ 16 июля 2012

это производит обратный отсортированный список шаров по частоте

balls.group_by { |b| b.color }
  .map { |k, v| [k, v.size] }
  .sort_by { |k, count| -count}
2 голосов
/ 17 марта 2010

Вот как бы я это сделал. Основная идея использует команду inject для накопления значений в хеш-код и основана на «12 - Построение гистограммы» в «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}

Есть два разных способа сделать это, в зависимости от того, сколько знаний вы хотите, чтобы inject () знал о ваших объектах.

2 голосов
/ 17 марта 2010

Как насчет:

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

2 голосов
/ 17 марта 2010

Ваш код неплох, но он неэффективен. Если бы я был вами, я бы искал решение, которое повторяет ваш массив только один раз, например:

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]

Это в основном то же самое, что и group_by, но в то же время подсчитывает группы и ведет учет какой группы является наибольшей (most_idx).

0 голосов
/ 17 марта 2010
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]}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...