104 votes

Comment compter les éléments de chaîne identiques dans un tableau Ruby ?

J'ai les éléments suivants Array = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]

Comment produire un décompte pour chaque élément identique ?

Where:
"Jason" = 2, "Judah" = 3, "Allison" = 1, "Teresa" = 1, "Michelle" = 1?

o produire un hachage Où ?

W hash = { "Jason" => 2, "Judah" => 3, "Allison" => 1, "Teresa" => 1, "Michelle" => 1 }

5 votes

Depuis Ruby 2.7, vous pouvez utiliser Enumerable#tally . Plus d'informations aquí .

133voto

Mauricio Points 3460
names.inject(Hash.new(0)) { |total, e| total[e] += 1 ;total}

vous donne

{"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1}

3 votes

+1 J'aime la réponse choisie, mais je préfère l'utilisation de l'injection et l'absence de variable "externe".

18 votes

Si vous utilisez each_with_object au lieu de inject vous ne devez pas retourner ( ;total ) au niveau du bloc.

15 votes

Pour la postérité, voici ce que @mfilej veut dire : array.each_with_object(Hash.new(0)){|string, hash| hash[string] += 1}

92voto

Dylan Markow Points 65796
names = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
counts = Hash.new(0)
names.each { |name| counts[name] += 1 }
# => {"Jason" => 2, "Teresa" => 1, ....

17voto

Jörg W Mittag Points 153275

Il existe en fait une structure de données qui permet de faire cela : MultiSet .

Malheureusement, il n'y a pas de MultiSet dans la bibliothèque de base ou la bibliothèque standard de Ruby, mais il y a quelques implémentations qui circulent sur le web.

C'est un excellent exemple de la façon dont le choix d'une structure de données peut simplifier un algorithme. En fait, dans cet exemple particulier, l'algorithme a même complètement disparaît. C'est littéralement juste :

Multiset.new(*names)

Et c'est tout. Exemple, en utilisant https://GitHub.Com/Josh/Multimap/ :

require 'multiset'

names = %w[Jason Jason Teresa Judah Michelle Judah Judah Allison]

histogram = Multiset.new(*names)
# => #<Multiset: {"Jason", "Jason", "Teresa", "Judah", "Judah", "Judah", "Michelle", "Allison"}>

histogram.multiplicity('Judah')
# => 3

Exemple, en utilisant http://maraigue.hhiro.net/multiset/index-en.php :

require 'multiset'

names = %w[Jason Jason Teresa Judah Michelle Judah Judah Allison]

histogram = Multiset[*names]
# => #<Multiset:#2 'Jason', #1 'Teresa', #3 'Judah', #1 'Michelle', #1 'Allison'>

0 votes

Le concept MultiSet provient-il des mathématiques ou d'un autre langage de programmation ?

2 votes

Andrew Grimm : Les deux mot "multiset" (de Bruijn, 1970) et le "multiset" (de Bruijn, 1970). concept (Dedekind 1888) a vu le jour en mathématiques. Multiset est régi par des règles mathématiques strictes et prend en charge les opérations typiques sur les ensembles (union, intersection, complément, ...) d'une manière qui est la plupart du temps cohérente avec les axiomes, les lois et les théorèmes de la théorie mathématique "normale" des ensembles, bien que certaines lois importantes ne soient pas compatibles avec les axiomes, les lois et les théorèmes de la théorie mathématique "normale" des ensembles. pas se maintiennent lorsque l'on essaie de les généraliser aux multi-ensembles. Mais cela va bien au-delà de ma compréhension de la question. Je les utilise comme une structure de données de programmation, et non comme un concept mathématique.

0 votes

Pour étendre un petit sur ce point : "... d'une manière qui est en grande partie cohérente avec les axiomes..." : Les ensembles "normaux" sont généralement définis formellement par un ensemble d'axiomes (hypothèses) appelé "théorie des ensembles de Zermelo-Frankel". Cependant, l'un de ces axiomes, le axiome d'extensionnalité affirme qu'un ensemble est défini précisément par ses membres - par exemple {A, A, B} = {A, B} . Il s'agit clairement d'une violation de la définition même des multi-ensembles !

6voto

Andrew Grimm Points 22996

Voici un style de programmation un peu plus fonctionnel :

array_with_lower_case_a = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
hash_grouped_by_name = array_with_lower_case_a.group_by {|name| name}
hash_grouped_by_name.map{|name, names| [name, names.length]}
=> [["Jason", 2], ["Teresa", 1], ["Judah", 3], ["Michelle", 1], ["Allison", 1]]

L'un des avantages de la group_by est que vous pouvez l'utiliser pour regrouper des éléments équivalents mais pas exactement identiques :

another_array_with_lower_case_a = ["Jason", "jason", "Teresa", "Judah", "Michelle", "Judah Ben-Hur", "JUDAH", "Allison"]
hash_grouped_by_first_name = another_array_with_lower_case_a.group_by {|name| name.split(" ").first.capitalize}
hash_grouped_by_first_name.map{|first_name, names| [first_name, names.length]}
=> [["Jason", 2], ["Teresa", 1], ["Judah", 3], ["Michelle", 1], ["Allison", 1]]

0 votes

Ai-je entendu parler de programmation fonctionnelle ? +1 :-) C'est sans aucun doute la meilleure façon de procéder, même si l'on peut dire qu'elle n'est pas efficace sur le plan de la mémoire. Notez également que Facets a une fréquence Enumerable#.

6voto

Shreyas Points 4871

Cela fonctionne.

arr = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
result = {}
arr.uniq.each{|element| result[element] = arr.count(element)}

2 votes

+1 Pour une approche différente -- bien que la complexité théorique soit pire -- O(n^2) (ce qui est important pour certaines valeurs de n ) y fait du travail supplémentaire (il doit compter pour "Judah" 3x, par exemple) ! Je suggère également each au lieu de map (le résultat de la carte est rejeté)

0 votes

Merci pour cela ! J'ai modifié la carte pour qu'elle corresponde à chaque élément, et j'ai unifié le tableau avant de le parcourir. Peut-être que le problème de la complexité est maintenant résolu ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X