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 :)
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/
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"]
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}
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.
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
}
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));
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
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))
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.
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
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},{})
));
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
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;
}
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;
}
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];
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
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>
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;
}
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
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 ;
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;
}
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
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
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)));
}
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]};
}
}, {})
}
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.