Как подсчитать дубликаты в массивах Ruby

Как вы считаете дубликаты в массиве ruby?

Например, если бы в моем массиве было три а, как я мог бы посчитать это


person Community    schedule 19.11.2009    source источник


Ответы (15)


Это даст повторяющиеся элементы в виде хэша с количеством вхождений для каждого повторяющегося элемента. Пусть говорит код:

#!/usr/bin/env ruby

class Array
  # monkey-patched version
  def dup_hash
    inject(Hash.new(0)) { |h,e| h[e] += 1; h }.select { 
      |k,v| v > 1 }.inject({}) { |r, e| r[e.first] = e.last; r }
  end
end

# unmonkeey'd
def dup_hash(ary)
  ary.inject(Hash.new(0)) { |h,e| h[e] += 1; h }.select { 
    |_k,v| v > 1 }.inject({}) { |r, e| r[e.first] = e.last; r }
end

p dup_hash([1, 2, "a", "a", 4, "a", 2, 1])
# {"a"=>3, 1=>2, 2=>2}

p [1, 2, "Thanks", "You're welcome", "Thanks", 
  "You're welcome", "Thanks", "You're welcome"].dup_hash
# {"You're welcome"=>3, "Thanks"=>3}
person miku    schedule 19.11.2009
comment
Больше не -1, а если серьезно... не делайте обезьяний патч, если нет другого способа сделать это. - person Bob Aman; 20.11.2009
comment
Какой смысл в финале .inject({}) { |r, e| r[e.first] = e.last; r }. select вернет хэш, так что все, что делает final inject, это ничего. - person Old Pro; 17.04.2014
comment
Если вам нужно сохранить элементы, которые встречаются только один раз, вы можете изменить v > 1 на v > 0. - person dotcomXY; 09.02.2017

Другая версия хеша с ключом для каждого элемента в вашем массиве и значением для количества каждого элемента.

a = [ 1, 2, 3, 3, 4, 3]
h = Hash.new(0)
a.each { | v | h.store(v, h[v]+1) }

# h = { 3=>3, 2=>1, 1=>1, 4=>1 } 
person Kim    schedule 19.11.2009
comment
Вкратце: [ 1, 2, 3, 3, 4, 3].reduce(Hash.new(0)) { |h, v| h.store(v, h[v] + 1); h }. #reduce обычно предпочтительнее #each, используемого для заполнения одной новой переменной. - person ejoubaud; 20.08.2014
comment
Это самое чистое решение, которое придерживается основных принципов метода Ruby. Я просто хотел бы отметить, что это также работает для смешанных массивов, а в Ruby любой объект может быть ключом! Попробуйте посчитать: [:a, :b, :a, 1, 10, 10, b, Боб, Боб, Бобби]. Это действительно работает. - person Usagi; 27.05.2016

Дано:

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

Мой любимый способ подсчета элементов:

counts = arr.group_by{|i| i}.map{|k,v| [k, v.count] }

# => [[1, 1], [2, 2], [3, 2], [4, 1], [5, 1]]

Если вам нужен хэш вместо массива:

Hash[*counts.flatten]

# => {1=>1, 2=>2, 3=>2, 4=>1, 5=>1}
person Ibrahim Muhammad    schedule 22.11.2012

Простой.

arr = [2,3,4,3,2,67,2]
repeats = arr.length - arr.uniq.length
puts repeats
person JRL    schedule 19.11.2009

Другой способ подсчета дубликатов массива:

arr= [2,2,3,3,2,4,2]

arr.group_by{|x| x}.map{|k,v| [k,v.count] }

результат

[[2, 4], [3, 2], [4, 1]]

person Ganesh Shrivas    schedule 06.05.2015

требуется 1.8.7+ для group_by

ary = %w{a b c d a e f g a h i b}
ary.group_by{|elem| elem}.select{|key,val| val.length > 1}.map{|key,val| key}
# => ["a", "b"]

с 1.9+ это может быть немного упрощено, потому что Hash#select вернет хэш.

ary.group_by{|elem| elem}.select{|key,val| val.length > 1}.keys
# => ["a", "b"]
person glenn jackman    schedule 19.11.2009

Для подсчета экземпляров одного элемента используйте инъекцию

array.inject(0){|count,elem| elem == value ? count+1 : count}
person Chris    schedule 15.12.2009

А как насчет грэпа?

arr = [1, 2, "Thanks", "You're welcome", "Thanks", "You're welcome", "Thanks", "You're welcome"]

arr.grep('Thanks').size # => 3
person fro_oo    schedule 14.03.2013

Это просто:

words = ["aa","bb","cc","bb","bb","cc"]

Однострочное простое решение:

words.each_with_object(Hash.new(0)) { |word,counts| counts[word] += 1 }

Меня устраивает.

Спасибо!!

person Manish Shrivastava    schedule 28.05.2014

Я не думаю, что есть встроенный метод. Если все, что вам нужно, это общее количество дубликатов, вы можете взять a.length - a.uniq.length. Если вам нужно количество отдельных элементов, попробуйте
a.select {|e| e == my_element}.length.

person Thom Smith    schedule 19.11.2009

Улучшение ответа @Kim:

arr = [1, 2, "a", "a", 4, "a", 2, 1]
Hash.new(0).tap { |h| arr.each { |v| h[v] += 1 } }
# => {1=>2, 2=>2, "a"=>3, 4=>1}
person Cristiano Mendonça    schedule 27.01.2016

Код Ruby для получения повторяющихся элементов в массиве:

numbers = [1,2,3,1,2,0,8,9,0,1,2,3]
similar =  numbers.each_with_object([]) do |n, dups|
    dups << n if seen.include?(n)
    seen << n 
end
print "similar --> ", similar
person sounish nath    schedule 06.11.2018

Другой способ сделать это — использовать each_with_object:

a = [ 1, 2, 3, 3, 4, 3]

hash = a.each_with_object({}) {|v, h|
  h[v] ||= 0
  h[v] += 1
}

# hash = { 3=>3, 2=>1, 1=>1, 4=>1 } 

Таким образом, вызов несуществующего ключа, такого как hash[5], вернет nil вместо 0 с решением Ким.

person pierrea    schedule 22.03.2019

Я использовал reduce/inject для этого в прошлом, как показано ниже.

array = [1,5,4,3,1,5,6,8,8,8,9]
array.reduce (Hash.new(0)) {|counts, el| counts[el]+=1; counts}

производит

=> {1=>2, 5=>2, 4=>1, 3=>1, 6=>1, 8=>3, 9=>1}
person rewolf    schedule 02.11.2016

Решение Ruby ›= 2.7 здесь:

Добавлен новый метод .tally.

Подсчитывает коллекцию, т. е. подсчитывает количество вхождений каждого элемента. Возвращает хэш с элементами коллекции в качестве ключей и соответствующими счетчиками в качестве значений.

Итак, теперь вы сможете:

["a", "b", "c", "b"].tally  #=> {"a"=>1, "b"=>2, "c"=>1}
person Sharvy Ahmed    schedule 14.03.2021