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

En Javascript, j'essaie de prendre un tableau initial de valeurs numériques et de compter les éléments à l'intérieur. 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 que 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

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

5, 2, 9, 4

Le second contiendrait le nombre de fois que cet élément s'est produit dans le tableau initial:

3, 5, 1, 1

Parce 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 deux une fois.

J'ai beaucoup cherché une solution, mais rien ne semble fonctionner, et tout ce que j'ai essayé moi-même a fini par être ridiculement complexe. Toute aide serait appréciée!

Merci :)

142
demandé sur Emissary 2011-04-14 22:32:26

26 réponses

Voilà:

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émonstration en Direct: http://jsfiddle.net/simevidas/bnACW/

69
répondu Šime Vidas 2011-04-14 18:58:56

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 counts peut vous dire quel est le compte pour un nombre particulier:

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

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

keys(counts); // returns ["5", "2", "9", "4"]
146
répondu typeof 2017-08-04 17:22:52
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}
65
répondu adamse 2011-04-14 21:09:24

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

_.countBy(array);

Tels 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 seulement les nombres uniques, et leurs occurrences, respectivement. Mais dans mon expérience, l'objet d'origine est beaucoup plus facile à traiter.

56
répondu radicand 2018-01-01 15:50:06

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]];
}

Alors result ressemblera à:

{
    2: 5,
    4: 1,
    5: 3,
    9: 1
}
44
répondu mu is too short 2016-03-07 17:29:16

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 à l'Set constructeur de création d'une collection de unique valeurs. La syntaxe spread développe ensuite ces valeurs dans un nouveau tableau afin que nous puissions appeler map et 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é Map constructeur résultant en un itérable objet:

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

La grande chose à propos d'un objet Map est qu'il préserve les types de données-c'est - à-dire aCount.get(5) retournera 3 mais aCount.get("5") retournera undefined. Il permet également de tout valeur / type d'agir comme une clé sens cette solution permettra également de travailler avec un tableau d'objets.

function frequencies(/* {Array} */ a){
    return new Map([...new Set(a)].map(
        x => [x, a.filter(y => y === x).length]
    ));
}

let foo = { value: 'foo' },
    bar = { value: 'bar' },
    baz = { value: 'baz' };

let aNumbers = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4],
    aObjects = [foo, bar, foo, foo, baz, bar];

frequencies(aNumbers).forEach((val, key) => console.log(key + ': ' + val));
frequencies(aObjects).forEach((val, key) => console.log(key.value + ': ' + val));
34
répondu Emissary 2017-07-17 07:41:18

Je pense que c'est le moyen le 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
27
répondu Dmytro Kozlovskyi 2014-10-16 08:46:47

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))
20
répondu Vlad Bezden 2016-10-03 22:29:04

Si vous préférez une seule doublure.

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

Modifier (6/12/2015) : L'Explication de l'intérieur. countMap est une carte qui mappe un mot avec sa fréquence, que nous pouvons voir la fonction anonyme. Ce que reduce fait est d'appliquer la fonction avec des arguments comme tous les éléments du tableau et countMap étant passés 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.

18
répondu rjalfa 2015-06-12 15:22:09

Si vous utilisez un trait de 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 ces fonctions seront par défaut des fonctions JavaScript natives si elles sont disponibles

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

8
répondu jhnstn 2013-10-16 06:25:32

Basée sur réponse de @adamse et @pmandell (qui je upvote), dans ES6, vous pouvez le faire dans une ligne:

  • 2017 modifier: - je utiliser || 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},{})

));
7
répondu ESL 2017-05-23 11:47:31

La version ES6 devrait être beaucoup plus simplifiée (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 objet simple nous aidant à distinguer différents types d'éléments, ou bien tous les comptage sont basés sur des chaînes

7
répondu William Leung 2017-09-07 07:28:43

Vous pouvez étendre le prototype de tableau, comme ceci:

Array.prototype.frequencies = function() {
    var l = this.length, result = {all:[]};
    while (l--){
       result[this[l]] = result[this[l]] ? ++result[this[l]] : 1;
    }
    // all pairs (label, frequencies) to an array of arrays(2)
    for (var l in result){
       if (result.hasOwnProperty(l) && l !== 'all'){
          result.all.push([ l,result[l] ]);
       }
    }
    return result;
};

var freqs = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4].frequencies();
alert(freqs[2]); //=> 5
// or
var freqs = '1,1,2,one,one,2,2,22,three,four,five,three,three,five'
             .split(',')
             .frequencies();
alert(freqs.three); //=> 3

Vous pouvez également utiliser Array.map:

  Array.prototype.frequencies  = function () {
    var freqs = {sum: 0}; 
    this.map( function (a){ 
        if (!(a in this)) { this[a] = 1; } 
        else { this[a] += 1; }
        this.sum += 1;
        return a; }, freqs
    );
    return freqs;
  }
5
répondu KooiInc 2014-06-03 08:45:41

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 occurences...

function count(a){
 var result = {};
 for(var i in a){
  if(result[a[i]] == undefined) result[a[i]] = 0;
  result[a[i]]++;
 }
 return result;
}
5
répondu ElDoRado1239 2017-07-10 19:37:39
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 réponse comme ceci...

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 uniqueNums soient des nombres

var uniqueNums = Object.keys(answer).map(key => +key);
// uniqueNums => [2, 4, 5, 9];
4
répondu SoEzPz 2017-04-20 21:26:49

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
2
répondu Thomas Gotwig 2018-02-25 22:30:35

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>
1
répondu Wouter van Nifterick 2011-04-14 18:59:38

Essayez ceci:

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;
}
1
répondu Aamir Afridi 2012-08-02 12:01:09

Vous pouvez rendre cela beaucoup plus facile en étendant vos tableaux avec une fonction count. Cela fonctionne un peu comme Rails ' Array#count, Si vous le connaissez.

Array.prototype.count = function(obj){
    var count = this.length;
    if(typeof(obj) !== "undefined"){
        var array = this.slice(0), count = 0; // clone array and reset count
        for(i = 0; i < array.length; i++){
            if(array[i] == obj){
                count++;
            }
        }
    }
    return count;
}

Utilisation:

var array = ['a', 'a', 'b', 'c'];
array.count('a'); // => 2
array.count('b'); // => 1
array.count('d'); // => 0
array.count(); // => 4

Source (gist)

0
répondu zykadelic 2013-03-02 13:30:01

Tableau donné x j'.e x = ['boy','man','oldman','scout','pilot']; nombre d'occurrences d'un élément de 'man' est

x.length - x.toString().split(',man,').toString().split(',').length ;
0
répondu Shashank Reddy Arrabothu 2016-01-11 05:44:20

Je résolvais un problème similaire sur codewars 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 aussi l'entier lui-même. Je pense qu'il peut également être appliqué au tableau de chaînes.

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

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;
}
0
répondu Varun Upadhyay 2016-03-21 20:17:20

Il existe un moyen bien meilleur et facile 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 countBy est à documentation

0
répondu Eshwar Prasad Yaddanapudi 2017-01-04 05:50:07

En ce qui concerne mon commentaire demandant à @ Emissary un ajustement à sa solution. im ajoutant la façon dont je l'ai géré:

let distinctArr = yourArray.filter((curElement, index, array) => array.findIndex(t =>    t.prop1=== curElement.prop1 && t.prop2 === curElement.prop2 && t.prop3=== curElement.prop3) === index);
let distinctWithCount = [...new Set(distinctArr)].map(function(element){element.prop4 = yourArray.filter(t =>    t.prop1=== element.prop1 && t.prop2 === element.prop2 && t.prop2=== element.prop2).length;

Ce Que je fais ici, c'est de supprimer les doublons et d'enregistrer le tableau (distinctArr) puis de compter sur le tableau d'origine (yourArray) le temps que l'objet a été dupliqué et d'ajouter une 4ème propriété avec la valeur des occurrences

J'espère que cela aidera quelqu'un qui a besoin de cette solution spécifique Ofc il est fait avec ES6

0
répondu sharon gur 2017-04-04 15:30:25

Voici un moyen de compter les occurrences dans 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é quantity de chaque objet dans le 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)));
}
0
répondu nate_js 2017-07-03 03:34:01
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]};
      }
    }, {})
}
0
répondu José Salgado 2018-08-28 20:37:02

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 le trier d'abord si vous voulez un résultat alphabétique, mais si vous voulez préserver 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.

-1
répondu MangoPapa7 2016-06-04 23:55:04