Ruby 如何在数组中查找出现次数最多的项

Ruby 如何在数组中查找出现次数最多的项,ruby,arrays,Ruby,Arrays,如何在数组中找到出现次数最多的项 [1, 1, 1, 2, 3].mode => 1 ['cat', 'dog', 'snake', 'dog'].mode => dog 首先构建一个哈希映射,将数组中的每个值映射到它的频率 arr = [1, 1, 1, 2, 3] freq = arr.inject(Hash.new(0)) { |h,v| h[v] += 1; h } #=> {1=>3, 2=>1, 3=>1} …然后使用频率表查找频率最高的元

如何在数组中找到出现次数最多的项

[1, 1, 1, 2, 3].mode
=> 1

['cat', 'dog', 'snake', 'dog'].mode
=> dog

首先构建一个哈希映射,将数组中的每个值映射到它的频率

arr = [1, 1, 1, 2, 3]

freq = arr.inject(Hash.new(0)) { |h,v| h[v] += 1; h }
#=> {1=>3, 2=>1, 3=>1}
…然后使用频率表查找频率最高的元素:

arr.max_by { |v| freq[v] }
#=> 1
这只是一个简单的索引器。您可以使用任何类型的基于符号/字符串的标识符替换[2,2,1..]数组,这对对象不起作用,您需要引入更复杂的内容,但这已经足够简单了


重新阅读您的问题,这个解决方案有点设计过度,因为它将返回所有事件的索引,而不仅仅是最频繁的事件。

虽然我喜欢grep解决方案的优雅,并提醒(或教)我一个我已经忘记(或完全忽略)的枚举方法,但它很慢,很慢,很慢。我100%同意创建
Array#mode
方法是一个好主意,但是-这是Ruby,我们不需要作用于数组的函数库,我们可以创建一个mixin,将必要的函数添加到数组类本身

但是
inject(Hash)
替代方法使用了一种排序,我们也不需要这种排序:我们只需要出现频率最高的值

这两种解决方案都不能解决模式中可能存在多个值的可能性。也许这不是问题中所说的(不知道)。我想我想知道是否有平局,无论如何,我想我们可以在表现上有所提高

require 'benchmark'

class Array
  def mode1
    sort_by {|i| grep(i).length }.last
  end
  def mode2
    freq = inject(Hash.new(0)) { |h,v| h[v] += 1; h }
    sort_by { |v| freq[v] }.last    
  end
  def mode3
    freq = inject(Hash.new(0)) { |h,v| h[v] += 1; h }
    max = freq.values.max                   # we're only interested in the key(s) with the highest frequency
    freq.select { |k, f| f == max }         # extract the keys that have the max frequency
  end
end

arr = Array.new(1_000) { |i| rand(100) }    # something to test with

Benchmark.bm(30) do |r|
  res = {}
  (1..3).each do |i|
    m = "mode#{i}"
    r.report(m) do
      100.times do
        res[m] = arr.send(m).inspect
      end
    end
  end
  res.each { |k, v| puts "%10s = %s" % [k, v] }
end
下面是示例运行的输出:

                                user     system      total        real
mode1                          34.375000   0.000000  34.375000 ( 34.393000)
mode2                           0.359000   0.000000   0.359000 (  0.359000)
mode3                           0.219000   0.000000   0.219000 (  0.219000)
     mode1 = 41
     mode2 = 41
     mode3 = [[41, 17], [80, 17], [72, 17]]
“优化”模式3占用了前一记录保持者60%的时间。还要注意多个最频繁的条目


几个月后,我注意到,这提供了:

def mode4
  group_by{|i| i}.max{|x,y| x[1].length <=> y[1].length}[0]
end

因此,如果性能非常关键,请对Ruby版本和操作系统上的选项进行基准测试

我找到了一个更快的方法。试试这个:

  class Array
    def mode4
      group_by{|i| i}.max{|x,y| x[1].length <=> y[1].length}[0]
    end
  end

这是这个问题的重复 “”

以下是该问题的解决方案:

group_by { |n| n }.values.max_by(&:size).first
这个版本似乎比Nilesh C的答案还要快。下面是我用来对其进行基准测试的代码(OSX10.6Core22.4GHzMB)

Mike Woodhouse(原始)基准测试代码的荣誉:

class Array
   def mode1
     group_by { |n| n }.values.max_by(&:size).first
   end
   def mode2
     freq = inject(Hash.new(0)) { |h,v| h[v] += 1; h }
     max = freq.values.max                   # we're only interested in the key(s) with the highest frequency
     freq.select { |k, f| f == max }         # extract the keys that have the max frequency
   end
end

arr = Array.new(1_0000) { |i| rand(100000) }    # something to test with

Benchmark.bm(30) do |r|
    (1..2).each do |i| r.report("mode#{i}") { 100.times do arr.send("mode#{i}").inspect; end }; end
end
以下是基准测试的结果:

                                user     system      total        real
mode1                           1.830000   0.010000   1.840000 (  1.876642)
mode2                           2.280000   0.010000   2.290000 (  2.382117)
 mode1 = 70099
 mode2 = [[70099, 3], [70102, 3], [51694, 3], [49685, 3], [38410, 3], [90815, 3], [30551, 3], [34720, 3], [58373, 3]]

正如你所看到的,这个版本大约快了20%,但要注意忽略领带。我也喜欢它的简洁,我个人使用它时没有到处打补丁

下面是另一个版本,它确实为您提供了领带作为一种模式:

def mode
  group_by {|x| x}.group_by {|k,v| v.size}.sort.last.last.map(&:first)
end

换句话说,将这些值分组,然后根据值的数量对这些kv对进行分组,然后对这些kv对进行排序,取最后一个(最高)大小的组,然后展开其值。如果你试图避免学习,我喜欢分组(你不应该这样做…)

但如果我以前读过这个答案,现在我对“注射”一无所知,你需要知道“注射”


甚至不需要考虑频率映射。

Ruby版本>=2.7将有

array.max_by { |i| array.count(i) }
清点收藏。返回一个散列,其中键是元素 这些值是集合中 与钥匙相对应

那么,你能做什么

[1, 1, 1, 2, 3].tally
# => {1=>3, 2=>1, 3=>1} 

你要问的是所谓的“模式”。方法“模式”在Rails 4中不起作用:(我在这里找到答案=>:)@romas8.38-39-谢谢,我以为我疯了。这似乎是另一个必须扔掉的有用东西,用来破坏工作代码。有人需要分道扬镳,把所有好的部分都放回原处。与其只提供代码答案,不如添加一个关于你的答案如何解决问题的解释,这将有助于你的读者学习。谢谢,你帮助了我!您的代码只返回最频繁的值。我对它做了一些修改,以首先返回按max排序的所有值:array.sort_by{u|u | array.count(u)}.reverseThis是O(n*n),接受的答案是O(n),或者可能是
freq.max_by{u,v | v}。首先
作为最后一行。如果您喜欢一个在线的话,您也可以使用{u对象(Hash.new 0(0)){v,h | h+=max}=1执行
arr.u[5,6,(1,2,(3,4,(7,8,(7,8,(1,8,(1,8,(1,1,2)1,4,(7,8,(1,1,4)7,8,(7,8,(1,2)7,7,8,(1,2)7,8,(1,2]
/code>编码>编码>计数器1=计数。计数。计数。计数。计数。计数。计数。计数。计数。计数。计数。计数。计数。计数。计数。每一个。每一个带有U带有U带有U对象(U对象(U对象(哈希。哈希。新(哈希。新(哈希。新(哈希。新(哈希。新(哈希。新(哈希。新(哈希。新(新(0。新(新(新(0)(新(0。新(0。新(0。新(0。新(新(新(新(0)的)。新(新(新(0)的)的)的)的)的)的)的)的它,它的|[它,它的长度]}[编码><编码><编码><编码><编码><编码><编码><编码>计数器4=到(U)计数。注射注射注射(哈希.新(0)){{h,v | h[v[v]+=1;h<编码><编码><编码><编码><编码>p count4.计数器4.计数器4.计数器4=到(到(到)到(到)计数.新(0)的(0){{h,h,v[v[v]h[v[v]h[v]h[v][v][v]h[v]+[v]h[v]+=1;h[v]=1;h[v]7}}}{{1;1;h}}}h}1;1;h}<编码><编码><编码><编码><编码><编码><编码><编码><编码><编码><编码><编码><编码;n}.values.max_by(&:size).首先
p max1
哈…………有很多方法可以做到,但最快的方法是使用堆栈。看看ruby的新功能!这是唯一的答案,只有一行代码。+1
def mode
  group_by {|x| x}.group_by {|k,v| v.size}.sort.last.last.map(&:first)
end
words = ['cat', 'dog', 'snake', 'dog']
count = Hash.new(0)

words.each {|word| count[word] += 1}
count.sort_by { |k,v| v }.last
def mode(array)

    count = []  # Number of times element is repeated in array
    output = [] 
    array.compact!
    unique = array.uniq
    j=0

    unique.each do |i|
        count[j] = array.count(i)
        j+=1
    end
    k=0
    count.each do |i|
        output[k] = unique[k] if i == count.max
        k+=1
    end  

    return output.compact.inspect
end

p mode([3,3,4,5]) #=> [3]

p mode([1,2,3]) #=> [1,2,3]

p mode([0,0,0,0,0,1,2,3,3,3,3,3]) #=> [0,3]

p mode([-1,-1,nil,nil,nil,0]) #=> [-1]

p mode([-2,-2,3,4,5,6,7,8,9,10,1000]) #=> [-2]
arr = [ 1, 3, 44, 3 ]
most_frequent_item = arr.uniq.max_by{ |i| arr.count( i ) }
puts most_frequent_item
#=> 3
array.max_by { |i| array.count(i) }
[1, 1, 1, 2, 3].tally
# => {1=>3, 2=>1, 3=>1}