Comptage des occurrences / fréquence des éléments du tableau

218

En Javascript, j'essaie de prendre un tableau initial de valeurs numériques et de compter les éléments qu'il contient. Idéalement, le résultat serait deux nouveaux tableaux, le premier spécifiant chaque élément unique et le second contenant le nombre de fois où chaque élément se produit. Cependant, je suis ouvert aux suggestions sur le format de la sortie.

Par exemple, si le tableau initial était:

5, 5, 5, 2, 2, 2, 2, 2, 9, 4

Ensuite, deux nouveaux tableaux seraient créés. Le premier contiendrait le nom de chaque élément unique:

5, 2, 9, 4

La seconde contiendrait le nombre de fois où cet élément s'est produit dans le tableau initial:

3, 5, 1, 1

Étant donné que le nombre 5 se produit trois fois dans le tableau initial, le nombre 2 se produit cinq fois et 9 et 4 apparaissent tous les deux une fois.

J'ai beaucoup cherché une solution, mais rien ne semble fonctionner, et tout ce que j'ai essayé moi-même s'est révélé ridiculement complexe. Toute aide serait appréciée!

Merci :)

Jack W
la source
8
Si tout ce dont vous aviez besoin était de voir si une valeur n'apparaissait qu'une seule fois (au lieu de deux fois ou plus), vous pourriez utiliserif (arr.indexOf(value) == arr.lastIndexOf(value))
Rodrigo
1
Nous pouvons utiliser ramda.jspour y parvenir la voie facile. const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]; R.countBy(r=> r)(ary)
Eshwar Prasad Yaddanapudi
arr.filter(x => x===5).lengthretournerait 3pour indiquer qu'il y a «3» cinq dans le tableau.
noobninja

Réponses:

94

Voici:

function foo(arr) {
    var a = [], b = [], prev;

    arr.sort();
    for ( var i = 0; i < arr.length; i++ ) {
        if ( arr[i] !== prev ) {
            a.push(arr[i]);
            b.push(1);
        } else {
            b[b.length-1]++;
        }
        prev = arr[i];
    }

    return [a, b];
}

Démo en direct: http://jsfiddle.net/simevidas/bnACW/

Remarque

Cela modifie l'ordre du tableau d'entrée d'origine à l'aide de Array.sort

Šime Vidas
la source
24
a un effet secondaire de trier le tableau (les effets secondaires sont mauvais), le tri l'est également O(N log(N))et le gain d'élégance n'en vaut pas la peine
ninjagecko
1
@ninja Quelle autre réponse préférez-vous?
Šime Vidas
En l'absence d'une belle primitive de haut niveau provenant d'une bibliothèque tierce, j'implémenterais normalement cela comme la reduceréponse. J'étais sur le point de soumettre une telle réponse avant de voir qu'elle existait déjà. Néanmoins, la counts[num] = counts[num] ? counts[num]+1 : 1réponse fonctionne également (équivalente à la if(!result[a[i]])result[a[i]]=0réponse, qui est plus élégante mais moins facile à lire); ces réponses peuvent être modifiées pour utiliser une version "plus agréable" de la boucle for, peut-être une boucle for tierce, mais j'ai en quelque sorte ignoré cela puisque les boucles for basées sur l'index standard sont malheureusement la valeur par défaut.
ninjagecko
2
@ninja, je suis d'accord. Ces réponses sont meilleures. Malheureusement, je ne peux pas refuser ma propre réponse.
Šime Vidas
Pour les petits tableaux, le tri sur place peut être plus rapide que la création d'un tableau associatif.
quant_dev
219

Vous pouvez utiliser un objet pour contenir les résultats:

var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
var counts = {};

for (var i = 0; i < arr.length; i++) {
  var num = arr[i];
  counts[num] = counts[num] ? counts[num] + 1 : 1;
}

console.log(counts[5], counts[2], counts[9], counts[4]);

Donc, maintenant votre objet count peut vous dire quel est le compte pour un nombre particulier:

console.log(counts[5]); // logs '3'

Si vous souhaitez obtenir un tableau de membres, utilisez simplement les keys()fonctions

keys(counts); // returns ["5", "2", "9", "4"]
Type de
la source
3
Il convient de noter que cette Object.keys()fonction n'est prise en charge que dans IE9 +, FF4 +, SF5 +, CH6 + mais Opera ne la prend pas en charge. Je pense que le plus gros bouchon d'exposition est IE9 + .
Robert Koritnik
19
De même, j'aime aussi counts[num] = (counts[num] || 0) + 1. De cette façon, vous n'avez qu'à écrire counts[num]deux fois au lieu de trois fois sur cette seule ligne.
robru
1
Ceci est une bonne réponse. Ceci est facilement résumé dans une fonction qui accepte un tableau et retourne un objet 'count'.
bitsand
Cela est vrai pour l'exemple spécifique de la question, mais pour le bien des googleurs, il convient de souligner que ce n'est pas toujours une technique sûre pour une utilisation plus large. Le stockage des valeurs en tant que clés d'objet pour les compter signifie que vous convertissez ces valeurs en chaînes, puis comptez cette valeur. [5, "5"]dira simplement que vous avez "5"deux fois. Ou compter des exemples d'objets différents va juste vous dire qu'il y en a beaucoup [object Object]. Etc. etc.
Jimbo Jonny
Comment pourrais-je alors filtrer l'objet retourné pour me montrer du plus haut au plus bas, ou du plus bas au plus grand compte sur un nombre
Ryan Holton
92
var a = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4].reduce(function (acc, curr) {
  if (typeof acc[curr] == 'undefined') {
    acc[curr] = 1;
  } else {
    acc[curr] += 1;
  }

  return acc;
}, {});

// a == {2: 5, 4: 1, 5: 3, 9: 1}
admirer
la source
39
acc[curr] ? acc[curr]++ : acc[curr] = 1;
pmandell
Merci, très belle solution;) ... et pour obtenir les tableaux "key" et "value":const keys = Object.keys(a); const values = Object.values(a);
ncenerar
79

Si vous utilisez un trait de soulignement ou un lodash, c'est la chose la plus simple à faire:

_.countBy(array);

Tel que:

_.countBy([5, 5, 5, 2, 2, 2, 2, 2, 9, 4])
=> Object {2: 5, 4: 1, 5: 3, 9: 1}

Comme indiqué par d'autres, vous pouvez ensuite exécuter les fonctions _.keys()et _.values()sur le résultat pour obtenir uniquement les nombres uniques et leurs occurrences, respectivement. Mais d'après mon expérience, l'objet d'origine est beaucoup plus facile à gérer.

radicand
la source
55

N'utilisez pas deux tableaux pour le résultat, utilisez un objet:

a      = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
result = { };
for(var i = 0; i < a.length; ++i) {
    if(!result[a[i]])
        result[a[i]] = 0;
    ++result[a[i]];
}

Cela resultressemblera alors à:

{
    2: 5,
    4: 1,
    5: 3,
    9: 1
}
mu est trop court
la source
48

Que diriez-vous d'une option ECMAScript2015.

const a = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];

const aCount = new Map([...new Set(a)].map(
    x => [x, a.filter(y => y === x).length]
));
aCount.get(5)  // 3
aCount.get(2)  // 5
aCount.get(9)  // 1
aCount.get(4)  // 1

Cet exemple transmet le tableau d'entrée au Setconstructeur en créant une collection de valeurs uniques . La syntaxe étendue étend ensuite ces valeurs dans un nouveau tableau afin que nous puissions appeler mapet traduire cela en un tableau bidimensionnel de [value, count]paires - c'est-à-dire la structure suivante:

Array [
   [5, 3],
   [2, 5],
   [9, 1],
   [4, 1]
]

Le nouveau tableau est ensuite passé au Mapconstructeur résultant en un objet itérable :

Map {
    5 => 3,
    2 => 5,
    9 => 1,
    4 => 1
}

La grande chose à propos d'un Mapobjet est qu'il préserve les types de données - c'est-à-dire aCount.get(5)qu'il reviendra 3mais aCount.get("5")qu'il reviendra undefined. Il permet également à n'importe quelle valeur / type d'agir comme une clé, ce qui signifie que cette solution fonctionnera également avec un tableau d'objets.

Émissaire
la source
avez-vous par hasard une réponse améliorée à cela juste pour un tableau d'objets? Im ayant du mal à essayer de le modifier pour un tableau d'objets, où vous venez de créer un nouveau tableau / carte / ensemble dans lequel vous supprimez les doublons et ajoutez une nouvelle valeur pour l'objet, disons appelé "duplicatedCount: value". j'ai réussi à supprimer les doublons dans mon tableau d'objets imbriqués de cette réponse stackoverflow.com/a/36744732
sharon gur
Setutilise des références d'objet pour l'unicité et n'offre aucune API pour la comparaison d' objets "similaires" . Si vous souhaitez utiliser cette approche pour une telle tâche, vous aurez besoin d'une fonction de réduction intermédiaire qui garantit un tableau d'instances uniques. Ce n'est pas le plus efficace mais j'ai rassemblé un exemple rapide ici .
Emissaire
Merci d'avoir répondu! mais je l'ai résolu un peu différemment. si vous pouvez voir la réponse que j'ai ajoutée ici stackoverflow.com/a/43211561/4474900 j'ai donné un exemple de ce que j'ai fait. cela fonctionne bien, mon cas avait un objet complexe à comparer. ne sais pas cependant l'efficacité de ma solution
sharon gur
8
Cela pourrait utiliser de belles nouvelles structures de données mais a un temps d'exécution en O ( ) alors qu'il existe ici de nombreux algorithmes simples qui le résolvent dans O ( n ).
raphinesse
41

Je pense que c'est la façon la plus simple de compter les occurrences avec la même valeur dans le tableau.

var a = [true, false, false, false];
a.filter(function(value){
    return value === false;
}).length
Dmytro Kozlovskyi
la source
9
ou a.filter(value => !value).lengthavec la nouvelle syntaxe js
t3chb0t
Ne répond pas à la question.
Ry-
36

Solution ES6 à une ligne. Tant de réponses utilisant l'objet comme carte mais je ne vois personne utiliser une vraie carte

const map = arr.reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());

Utilisation map.keys() pour obtenir des éléments uniques

Utilisation map.values() pour obtenir les occurrences

Utilisez map.entries()pour obtenir les paires [élément, fréquence]

var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]

const map = arr.reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());

console.info([...map.keys()])
console.info([...map.values()])
console.info([...map.entries()])

corashina
la source
Javascript moderne obtient le meilleur de tous les mondes
Igniter
31

const data = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]

function count(arr) {
  return arr.reduce((prev, curr) => (prev[curr] = ++prev[curr] || 1, prev), {})
}

console.log(count(data))

Vlad Bezden
la source
4
Quelqu'un voudrait-il expliquer cela (prev [curr] = ++ prev [curr] || 1, prev)?
Souljacker
6
L' opérateur virgule «évalue chacun de ses opérandes (de gauche à droite) et renvoie la valeur du dernier opérande», ce qui incrémente la valeur de prev [curr] (ou l'initialise à 1), puis renvoie prev.
ChrisV
mais la sortie est-elle un tableau?
Francesco
20

Si vous préférez une doublure simple.

arr.reduce(function(countMap, word) {countMap[word] = ++countMap[word] || 1;return countMap}, {});

Edit (6/12/2015) : L'explication de l'intérieur. countMap est une carte qui mappe un mot avec sa fréquence, dont nous pouvons voir la fonction anonyme. Ce que fait réduire est d'appliquer la fonction avec des arguments comme tous les éléments du tableau et countMap étant transmis comme valeur de retour du dernier appel de fonction. Le dernier paramètre ({}) est la valeur par défaut de countMap pour le premier appel de fonction.

rjalfa
la source
1
Vous devez expliquer cela. cela en ferait une bien meilleure réponse pour que les gens puissent apprendre à l'utiliser dans d'autres cas d'utilisation.
Andrew Grothe
Une doublure unique qui supprime simplement le saut de ligne qui suivrait habituellement ;, {et }. ... D'ACCORD. Je pense qu'avec cette définition d'un liner, nous pouvons écrire Game of Life de Conway comme un "oneliner".
trincot
16

La version ES6 devrait être beaucoup plus simple (une autre solution d'une ligne)

let arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
let acc = arr.reduce((acc, val) => acc.set(val, 1 + (acc.get(val) || 0)), new Map());

console.log(acc);
// output: Map { 5 => 3, 2 => 5, 9 => 1, 4 => 1 }

Une carte au lieu d'un simple objet nous aidant à distinguer différents types d'éléments, ou bien tous les comptages sont basés sur des chaînes

William Leung
la source
8

Si vous utilisez le soulignement, vous pouvez suivre la route fonctionnelle

a = ['foo', 'foo', 'bar'];

var results = _.reduce(a,function(counts,key){ counts[key]++; return counts },
                  _.object( _.map( _.uniq(a), function(key) { return [key, 0] })))

donc votre premier tableau est

_.keys(results)

et le deuxième tableau est

_.values(results)

la plupart de ceux-ci seront par défaut des fonctions natives javascript si elles sont disponibles

démo: http://jsfiddle.net/dAaUU/

jhnstn
la source
8

Sur la base des réponses de @adamse et @pmandell (que j'ai voté), dans ES6, vous pouvez le faire en une seule ligne :

  • Édition 2017 : j'utilise ||pour réduire la taille du code et le rendre plus lisible.

var a=[7,1,7,2,2,7,3,3,3,7,,7,7,7];
alert(JSON.stringify(

a.reduce((r,k)=>{r[k]=1+r[k]||1;return r},{})

));


Il peut être utilisé pour compter les caractères :

var s="ABRACADABRA";
alert(JSON.stringify(

s.split('').reduce((a, c)=>{a[c]++?0:a[c]=1;return a},{})

));

ESL
la source
Il serait plus lisible si vous || 0(r,k)=>{r[k]=(r[k]||0)+1;return r}
utilisiez
Vous pouvez tout faire sur une seule ligne en JavaScript.
Ry-
Et pourquoi est-ce une mauvaise chose, @ Ry-?
ESL
Parfois, c'est plus clair sur plusieurs lignes, d'autres plus clair sur une seule ligne. C'est une question de "goût".
ESL
Je veux dire «dans ES6, vous pouvez le faire en une seule ligne» s'applique à chaque réponse, et vous pouvez également le faire dans ES5 en une seule ligne.
Ry-
5

Voici juste quelque chose de léger et facile pour les yeux ...

function count(a,i){
 var result = 0;
 for(var o in a)
  if(a[o] == i)
   result++;
 return result;
}

Edit: Et puisque vous voulez toutes les occurrences ...

function count(a){
 var result = {};
 for(var i in a){
  if(result[a[i]] == undefined) result[a[i]] = 0;
  result[a[i]]++;
 }
 return result;
}
ElDoRado1239
la source
1
La question demandait le dénombrement de tous les éléments.
Ry-
Ok, j'ai raté ça. Devrait être corrigé maintenant.
ElDoRado1239
5

Voici donc comment je le ferais avec certaines des dernières fonctionnalités javascript:

Tout d'abord, réduisez le tableau à l'un Mapdes nombres:

let countMap = array.reduce(
  (map, value) => {map.set(value, (map.get(value) || 0) + 1); return map}, 
  new Map()
)

En utilisant a Map, votre tableau de départ peut contenir n'importe quel type d'objet et les nombres seront corrects. Sans Map, certains types d'objets vous donneront d'étranges dénombrements. Voir la Mapdocumentation pour plus d'informations sur les différences.

Cela peut également être fait avec un objet si toutes vos valeurs sont des symboles, des nombres ou des chaînes:

let countObject = array.reduce(
  (map, value) => { map[value] = (map[value] || 0) + 1; return map },
  {}
)

Ou légèrement plus sophistiqué de manière fonctionnelle sans mutation, en utilisant la syntaxe de déstructuration et de propagation d'objet:

let countObject = array.reduce(
  (value, {[value]: count = 0, ...rest}) => ({ [value]: count + 1, ...rest }),
  {}
)

À ce stade, vous pouvez utiliser le Map objet ou pour vos décomptes (et la carte est directement itérable, contrairement à un objet), ou la convertir en deux tableaux.

Pour le Map:

countMap.forEach((count, value) => console.log(`value: ${value}, count: ${count}`)

let values = countMap.keys()
let counts = countMap.values()

Ou pour l'objet:

Object
  .entries(countObject) // convert to array of [key, valueAtKey] pairs
  .forEach(([value, count]) => console.log(`value: ${value}, count: ${count}`)

let values = Object.keys(countObject)
let counts = Object.values(countObject)
Garrett Motzner
la source
4
var array = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];

function countDuplicates(obj, num){
  obj[num] = (++obj[num] || 1);
  return obj;
}

var answer = array.reduce(countDuplicates, {});
// answer => {2:5, 4:1, 5:3, 9:1};

Si vous voulez toujours deux tableaux, vous pouvez utiliser une réponse comme celle-ci ...

var uniqueNums = Object.keys(answer);
// uniqueNums => ["2", "4", "5", "9"];

var countOfNums = Object.keys(answer).map(key => answer[key]);
// countOfNums => [5, 1, 3, 1];

Ou si vous voulez que les numéros uniques soient des nombres

var uniqueNums = Object.keys(answer).map(key => +key);
// uniqueNums => [2, 4, 5, 9];
SoEzPz
la source
1
es6 / 7 rend tout cela beaucoup plus agréable. Vous pouvez également réduire à la Mapplace, car cela évitera la conversion en caractères que l'utilisation d'un nombre comme clé d'objet (conversion en chaîne). const answer = array.reduce((a, e) => a.set(e, (a.get(e) || 0) + 1), new Map())Vous pouvez obtenir answer.keys()les clés et answer.values()les valeurs sous forme de tableaux. [...answer]vous donnera un grand tableau avec toutes les clés / valeurs sous forme de tableaux 2D.
Josh de Qaribou le
4

Solution ES6 avec réduction (fixe):

const arr = [2, 2, 2, 3, 2]

const count = arr.reduce((pre, cur) => (cur === 2) ? ++pre : pre, 0)
console.log(count) // 4

Thomas Gotwig
la source
Je ne sais pas comment un nombre représente le nombre de chaque élément de tableau distinct comme la question posée.
Ry-
4

Edit 2020 : c'est une assez vieille réponse (neuf ans). L'extension du natif prototypegénérera toujours une discussion . Bien que je pense que le programmeur est libre de choisir son propre style de programmation, voici une approche (plus moderne) du problème sans l'étendre Array.prototype:

{
  // create array with some pseudo random values (1 - 5)
  const arr = Array.from({length: 100})
    .map( () => Math.floor(1 + Math.random() * 5) );
  // frequencies using a reducer
  const arrFrequencies = arr.reduce((acc, value) => 
      ({ ...acc, [value]: acc[value] + 1 || 1}), {} )
  console.log(`Value 4 occurs ${arrFrequencies[4]} times in arrFrequencies`);

  // bonus: restore Array from frequencies
  const arrRestored = Object.entries(arrFrequencies)
    .reduce( (acc, [key, value]) => acc.concat(Array(value).fill(+key)), [] );
  console.log(arrRestored.join());  
}
.as-console-wrapper { top: 0; max-height: 100% !important; }

L'ancienne (2011) réponse: vous pouvez étendre Array.prototype, comme ceci:

KooiInc
la source
2

Ma solution avec ramda:

const testArray = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]

const counfFrequency = R.compose(
  R.map(R.length),
  R.groupBy(R.identity),
)

counfFrequency(testArray)

Lien vers REPL.

Michal
la source
2

Solution utilisant une carte avec une complexité temporelle O (n) .

var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];

const countOccurrences = (arr) => {
    const map = {};
    for ( var i = 0; i < arr.length; i++ ) {
        map[arr[i]] = ~~map[arr[i]] + 1;
    }
    return map;
}

Démo: http://jsfiddle.net/simevidas/bnACW/

Sardorjon Vakkosov
la source
Mon vote positif pour vous, cela fonctionne comme du beurre avec une complexité temporelle O (n)
Vishal Shetty
1

Il existe un moyen bien meilleur et plus simple de le faire en utilisant ramda.js. Exemple de code ici

const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]; R.countBy(r=> r)(ary) la documentation de countBy est à la documentation

Eshwar Prasad Yaddanapudi
la source
1

En utilisant MAP, vous pouvez avoir 2 tableaux dans la sortie: l'un contenant les occurrences et l'autre contenant le nombre d'occurrences.

const dataset = [2,2,4,2,6,4,7,8,5,6,7,10,10,10,15];
let values = [];
let keys = [];

var mapWithOccurences = dataset.reduce((a,c) => {
  if(a.has(c)) a.set(c,a.get(c)+1);
  else a.set(c,1);
  return a;
}, new Map())
.forEach((value, key, map) => {
  keys.push(key);
  values.push(value);
});


console.log(keys)
console.log(values)

Melchia
la source
0

Consultez le code ci-dessous.

<html>
<head>
<script>
// array with values
var ar = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];

var Unique = []; // we'll store a list of unique values in here
var Counts = []; // we'll store the number of occurances in here

for(var i in ar)
{
    var Index = ar[i];
    Unique[Index] = ar[i];
    if(typeof(Counts[Index])=='undefined')  
        Counts[Index]=1;
    else
        Counts[Index]++;
}

// remove empty items
Unique = Unique.filter(function(){ return true});
Counts = Counts.filter(function(){ return true});

alert(ar.join(','));
alert(Unique.join(','));
alert(Counts.join(','));

var a=[];

for(var i=0; i<Unique.length; i++)
{
    a.push(Unique[i] + ':' + Counts[i] + 'x');
}
alert(a.join(', '));

</script>
</head>
<body>

</body>
</html>
Wouter van Nifterick
la source
0

Essaye ça:

Array.prototype.getItemCount = function(item) {
    var counts = {};
    for(var i = 0; i< this.length; i++) {
        var num = this[i];
        counts[num] = counts[num] ? counts[num]+1 : 1;
    }
    return counts[item] || 0;
}
Aamir Afridi
la source
0

Je résolvais un problème similaire sur les guerres de code et j'ai conçu la solution suivante qui a fonctionné pour moi.

Cela donne le nombre le plus élevé d'un entier dans un tableau et également l'entier lui-même. Je pense qu'il peut également être appliqué au tableau de chaînes.

Pour trier correctement les chaînes, retirez le function(a, b){return a-b}de l'intérieur de la sort()portion

function mostFrequentItemCount(collection) {
    collection.sort(function(a, b){return a-b});
    var i=0;
    var ans=[];
    var int_ans=[];
    while(i<collection.length)
    {
        if(collection[i]===collection[i+1])
        {
            int_ans.push(collection[i]);
        }
        else
        {
            int_ans.push(collection[i]);
            ans.push(int_ans);
            int_ans=[];
        }
        i++;
    }

    var high_count=0;
    var high_ans;

    i=0;
    while(i<ans.length)
    {
        if(ans[i].length>high_count)
        {
            high_count=ans[i].length;
            high_ans=ans[i][0];
        }
        i++;
    }
    return high_ans;
}
Varun Upadhyay
la source
0

Voici un moyen de compter les occurrences à l'intérieur d'un tableau d'objets. Il place également le contenu du premier tableau dans un nouveau tableau pour trier les valeurs afin que l'ordre dans le tableau d'origine ne soit pas perturbé. Ensuite, une fonction récursive est utilisée pour parcourir chaque élément et compter la propriété de quantité de chaque objet à l'intérieur du tableau.

var big_array = [
  { name: "Pineapples", quantity: 3 },
  { name: "Pineapples", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Limes", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Pineapples", quantity: 2 },
  { name: "Pineapples", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Bananas", quantity: 5 },
  { name: "Coconuts", quantity: 1 },
  { name: "Lemons", quantity: 2 },
  { name: "Oranges", quantity: 1 },
  { name: "Lemons", quantity: 1 },
  { name: "Limes", quantity: 1 },
  { name: "Grapefruit", quantity: 1 },
  { name: "Coconuts", quantity: 5 },
  { name: "Oranges", quantity: 6 }
];

function countThem() {
  var names_array = [];
  for (var i = 0; i < big_array.length; i++) {
    names_array.push( Object.assign({}, big_array[i]) );
  }

  function outerHolder(item_array) {
    if (item_array.length > 0) {
      var occurrences = [];
      var counter = 0;
      var bgarlen = item_array.length;
      item_array.sort(function(a, b) { return (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0); });

      function recursiveCounter() {
        occurrences.push(item_array[0]);
        item_array.splice(0, 1);
        var last_occurrence_element = occurrences.length - 1;
        var last_occurrence_entry = occurrences[last_occurrence_element].name;
        var occur_counter = 0;
        var quantity_counter = 0;
        for (var i = 0; i < occurrences.length; i++) {
          if (occurrences[i].name === last_occurrence_entry) {
            occur_counter = occur_counter + 1;
            if (occur_counter === 1) {
              quantity_counter = occurrences[i].quantity;
            } else {
              quantity_counter = quantity_counter + occurrences[i].quantity;
            }
          }
        }

        if (occur_counter > 1) {
          var current_match = occurrences.length - 2;
          occurrences[current_match].quantity = quantity_counter;
          occurrences.splice(last_occurrence_element, 1);
        }

        counter = counter + 1;

        if (counter < bgarlen) {
          recursiveCounter();
        }
      }

      recursiveCounter();

      return occurrences;
    }
  }
  alert(JSON.stringify(outerHolder(names_array)));
}
nate_js
la source
0
function countOcurrences(arr){
    return arr.reduce((aggregator, value, index, array) => {
      if(!aggregator[value]){
        return aggregator = {...aggregator, [value]: 1};  
      }else{
        return aggregator = {...aggregator, [value]:++aggregator[value]};
      }
    }, {})
}
José Salgado
la source
Extrêmement inutile de copier l'objet à chaque fois. Crée un pire cas quadratique lorsqu'il peut être linéaire.
Ry-
0
var aa = [1,3,5,7,3,2,4,6,8,1,3,5,5,2,0,6,5,9,6,3,5,2,5,6,8];
var newArray = {};
for(var element of aa){
  if(typeof newArray[element] === 'undefined' || newArray[element] === null){
    newArray[element] = 1;
  }else{
    newArray[element] +=1;
  }
}

for ( var element in newArray){
  console.log( element +" -> "+ newArray[element]);
}
Dilraj Singh
la source
0

Cette question a plus de 8 ans et beaucoup, beaucoup de réponses ne prennent pas vraiment en compte ES6 et ses nombreux avantages.

Il est peut-être encore plus important de réfléchir aux conséquences de notre code pour la collecte des ordures / la gestion de la mémoire chaque fois que nous créons des tableaux supplémentaires, faisons des copies doubles ou triples de tableaux ou même convertissons des tableaux en objets. Ce sont des observations triviales pour les petites applications, mais si l'échelle est un objectif à long terme, réfléchissez-y attentivement.

Si vous avez juste besoin d'un "compteur" pour des types de données spécifiques et que le point de départ est un tableau (je suppose que vous voulez donc une liste ordonnée et profitez des nombreuses propriétés et méthodes proposées par les tableaux), vous pouvez simplement parcourir simplement array1 et remplir array2 avec les valeurs et le nombre d'occurrences de ces valeurs trouvées dans array1.

Aussi simple que cela.

Exemple de classe simple SimpleCounter (ES6) pour la programmation orientée objet et la conception orientée objet

class SimpleCounter { 

    constructor(rawList){ // input array type
        this.rawList = rawList;
        this.finalList = [];
    }

    mapValues(){ // returns a new array

        this.rawList.forEach(value => {
            this.finalList[value] ? this.finalList[value]++ : this.finalList[value] = 1;
        });

        this.rawList = null; // remove array1 for garbage collection

        return this.finalList;

    }

}

module.exports = SimpleCounter;
rags2riches
la source
Le fait de coller une fonction dans une classe sans raison ne la rend pas orientée objet, finalListn'a aucune raison d'être un tableau, et cela n'a aucun avantage par rapport à la faire correctement.
Ry-
-1

Voici une méthode classique de la vieille école pour compter les tableaux.

var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
var counted = [], count = [];
var i = 0, j = 0, k = 0;
while (k < arr.length) {
    if (counted.indexOf(arr[k]) < 0) {
        counted[i] = arr[k];
        count[i] = 0;
        for (j = 0; j < arr.length; j++) {
            if (counted[i] == arr[j]) {
                count[i]++;
            }
        }
        i++;
    } else {
        k++;
    }
}

Vous pouvez d'abord le trier si vous souhaitez un résultat alphabétique, mais si vous souhaitez conserver l'ordre dans lequel les données ont été saisies, essayez-le. Les boucles imbriquées peuvent être un peu plus lentes que certaines des autres méthodes de cette page.

MangoPapa7
la source