Найдите наиболее распространенную строку в массиве

У меня есть этот массив, например (размер является переменным):

   x = ["1.111", "1.122", "1.250", "1.111"]

и я должен найти самое общее значение ("1.111" в этом случае).

Существует ли простой способ сделать это?

Спасибо заранее!


РЕДАКТИРОВАНИЕ № 1: Спасибо всем за ответы!


РЕДАКТИРОВАНИЕ № 2: я изменил свой принятый ответ на основе информации о Z.E.D.'s. Поблагодарите всех снова!

20
задан Ju Nogueira 1 April 2010 в 18:37
поделиться

6 ответов

Ruby <2.2

#!/usr/bin/ruby1.8

def most_common_value(a)
  a.group_by do |e|
    e
  end.values.max_by(&:size).first
end

x = ["1.111", "1.122", "1.250", "1.111"]
p most_common_value(x)    # => "1.111"

Примечание: Enumberable.max_by является новым в Ruby 1.9, но был перенесен на 1.8.7

Ruby> = 2.2

Ruby 2.2 представляет метод Object # , с помощью которого мы можем сделать код более кратким:

def most_common_value(a)
  a.group_by(&:itself).values.max_by(&:size).first
end

Как патч обезьяны

Или как Enumerable # mode :

Enumerable.class_eval do
  def mode
    group_by do |e|
      e
    end.values.max_by(&:size).first
  end
end

["1.111", "1.122", "1.250", "1.111"].mode
# => "1.111"
43
ответ дан 29 November 2019 в 23:02
поделиться

Один проход через хэш для накопления счетчиков. Используйте .max (), чтобы найти хеш-запись с наибольшим значением.

#!/usr/bin/ruby

a = Hash.new(0)
["1.111", "1.122", "1.250", "1.111"].each { |num|
  a[num] += 1
}

a.max{ |a,b| a[1] <=> b[1] } # => ["1.111", 2]

или свести все в одну строку:

ary.inject(Hash.new(0)){ |h,i| h[i] += 1; h }.max{ |a,b| a[1] <=> b[1] } # => ["1.111", 2]

Если вы хотите вернуть только элемент, добавьте .first ():

ary.inject(Hash.new(0)){ |h,i| h[i] += 1; h }.max{ |a,b| a[1] <=> b[1] }.first # => "1.111"

Первый пример, который я использовал, показывает, как это обычно делается в Perl. Второй - более рубиновый. Оба работают со старыми версиями Ruby. Я хотел сравнить их, а также посмотреть, как решение Уэйна ускорит процесс, поэтому я протестировал с помощью теста:

#!/usr/bin/env ruby

require 'benchmark'

ary = ["1.111", "1.122", "1.250", "1.111"] * 1000 

def most_common_value(a)
  a.group_by { |e| e }.values.max_by { |values| values.size }.first
end

n = 1000
Benchmark.bm(20) do |x|
  x.report("Hash.new(0)") do
    n.times do 
      a = Hash.new(0)
      ary.each { |num| a[num] += 1 }
      a.max{ |a,b| a[1] <=> b[1] }.first
    end 
  end

  x.report("inject:") do
    n.times do
      ary.inject(Hash.new(0)){ |h,i| h[i] += 1; h }.max{ |a,b| a[1] <=> b[1] }.first
    end
  end

  x.report("most_common_value():") do
    n.times do
      most_common_value(ary)
    end
  end
end

Вот результаты:

                          user     system      total        real
Hash.new(0)           2.150000   0.000000   2.150000 (  2.164180)
inject:               2.440000   0.010000   2.450000 (  2.451466)
most_common_value():  1.080000   0.000000   1.080000 (  1.089784)
5
ответ дан 29 November 2019 в 23:02
поделиться

Вы можете отсортировать массив, а затем перебрать его один раз. В цикле просто отслеживайте текущий элемент и количество его просмотров. Когда список закончится или элемент изменится, установите max_count == count , если count> max_count . И, конечно же, отслеживайте, какой элемент имеет max_count .

4
ответ дан 29 November 2019 в 23:02
поделиться

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

Псевдокод:

["1.111", "1.122", "1.250", "1.111"].each { |num|
  count=your_hash_map.get(num)
  if(item==nil)
    hashmap.put(num,1)
  else
    hashmap.put(num,count+1)
}

Как уже упоминалось, сортировка может быть быстрее.

2
ответ дан 29 November 2019 в 23:02
поделиться

Использование функции значений хэшей по умолчанию:

>> x = ["1.111", "1.122", "1.250", "1.111"]
>> h = Hash.new(0)
>> x.each{|i| h[i] += 1 }
>> h.max{|a,b| a[1] <=> b[1] }
["1.111", 2]
2
ответ дан 29 November 2019 в 23:02
поделиться

Он вернет самое популярное значение в массиве

x.group_by{|a| a }.sort_by{|a,b| b.size<=>a.size}.first[0]

IE:

x = ["1.111", "1.122", "1.250", "1.111"]
# Most popular
x.group_by{|a| a }.sort_by{|a,b| b.size<=>a.size}.first[0]
#=> "1.111
# How many times
x.group_by{|a| a }.sort_by{|a,b| b.size<=>a.size}.first[1].size
#=> 2
0
ответ дан 29 November 2019 в 23:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: