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 d'occurrences de chaque élément. 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 seront créés. Le premier contiendrait le nom de chaque élément unique:
5, 2, 9, 4
La seconde contiendrait le nombre d'occurrences de cet élément dans le tableau initial:
3, 5, 1, 1
Étant donné que le nombre 5 apparaît trois fois dans la matrice initiale, le nombre 2 apparaît 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 moi-même essayé est devenu d'une complexité ridicule. Toute aide serait appréciée!
Merci :)
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
Ceci change l'ordre du tableau d'entrée d'origine en utilisant
Array.sort
Vous pouvez utiliser un objet pour conserver 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 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 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 l'ont souligné d'autres personnes, vous pouvez ensuite exécuter les fonctions _.keys()
et _.values()
sur le résultat pour obtenir uniquement les numéros uniques et leurs occurrences, respectivement. Mais selon mon expérience, l'objet original est beaucoup plus facile à gérer.
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
}
Je pense que c'est le moyen le plus simple de compter les occurrences avec la même valeur dans un 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))
La version ES6 devrait être beaucoup plus simple (une autre solution en 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, sinon tous les calculs sont basés sur des chaînes
Si vous utilisez un trait de soulignement, vous pouvez passer par 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 second tableau est
_.values(results)
la plupart de ces fonctions seront par défaut des fonctions javascript natives si elles sont disponibles
Sur la base de answer of @adamse and @pmandell (que je vote plus tôt), dans ES6 vous pouvez le faire en une ligne:
||
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},{})
));
Vous pouvez étendre le prototype Array, 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
Sinon, vous pouvez 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 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;
}
Solution ES6 à une ligne. Autant de réponses utilisant objet comme carte mais je ne vois personne utiliser une réelle Carte
const map = arr.reduce((acc, e) => acc.set(e, acc.get(e) + 1 || 1), new Map());
Utilisez map.keys()
pour obtenir des éléments uniques
Utilisez map.values()
pour obtenir les occurrences
Utilisez map.entries()
pour obtenir les paires [élément, fréquence]
Je suis un peu en retard à la fête mais j'espère qu'au moins une personne le trouvera utile.
var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]
const map = arr.reduce((acc, e) => acc.set(e, acc.get(e) + 1 || 1), new Map());
console.info(...map.keys())
console.info(...map.values())
console.info(...map.entries())
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 answer 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 nombres uniques 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
En ce qui concerne mon commentaire demandant @Emissary sur un ajustement à sa solution. En 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 est de supprimer les doublons et de sauvegarder le tableau (distinctArr), puis de compter sur le tableau original (yourArray) la durée de duplication de l'objet et d'ajouter une 4ème propriété avec la valeur des occurrences
J'espère que cela aidera pour quelqu'un qui a besoin de cette solution spécifique .__ Ofc il est fait avec ES6
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]};
}
}, {})
}
Juste un autre point de vue ...
let array = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]
let count = 0
let finalResult = []
array.sort().map((e, index)=>{
if(e==array[index+1]){
count++
} else {
count++
finalResult.Push([e+" => "+count])
count = 0
}
})
console.log(finalResult)
// output
// [ [ '2 => 5' ], [ '4 => 1' ], [ '5 => 3' ], [ '9 => 1' ] ]
Découvrez 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>
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;
}
Alors voici comment je le ferais avec certaines des dernières fonctionnalités javascript:
Tout d’abord, réduisez le tableau à un Map
des nombres:
let countMap = array.reduce(
(map, value) => {map.set(value, (map.get(value) || 0) + 1); return map},
new Map
)
En utilisant une Map
, votre tableau de départ peut contenir n’importe quel type d’objet et le nombre sera correct. Sans Map
, certains types d’objets vous donneront d’étranges comptages . Consultez la Map
docs 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 raffiné 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 la variable Map
ou un objet pour vos comptages (et la carte est directement itérable, contrairement à un objet), ou la convertir en deux tableaux.
Pour la 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)
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]);
}
Vous pouvez rendre cela beaucoup plus facile en étendant vos tableaux avec une fonction count
. Cela fonctionne un peu comme le Array#count
de Rails, si vous le connaissez bien.
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;
}
Usage:
var array = ['a', 'a', 'b', 'c'];
array.count('a'); // => 2
array.count('b'); // => 1
array.count('d'); // => 0
array.count(); // => 4
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é de quantité 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)));
}
Pour ce faire, il existe un moyen beaucoup plus simple et efficace d'utiliser ramda.js
. Exemple de code ici
const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
R.countBy(r=> r)(ary)
countBy la documentation est à documentation
Voici la solution la plus simple
const data = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
let occurance_arr=[];
const aCount = [...new Set(data)].map(x => {
occurance_arr.Push(data.filter(y=> y==x).length)
});
console.log(occurance_arr); //[3, 5, 1, 1]
Je résolvais un problème similaire sur les codewars et 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 le nombre entier lui-même. Je pense que cela peut aussi s'appliquer au tableau de chaînes.
Pour trier correctement les chaînes, supprimez la function(a, b){return a-b}
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;
}
En utilisantMAPvous 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)
Cette question a plus de 8 ans et beaucoup de réponses ne tiennent pas vraiment en tenant compte de ES6 et de ses nombreux avantages.
Il est peut-être encore plus important de penser aux conséquences de notre code pour la gestion de la récupération de place/de la mémoire chaque fois que nous créons des tableaux supplémentaires. double ou triple copie de tableaux ou même convertir des tableaux en objets. Ce sont des observations triviales pour de petites applications, mais si l’échelle est un objectif à long terme, réfléchissez-y à fond.
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 tirez parti des nombreuses propriétés et méthodes offertes par les tableaux), vous pouvez simplement effectuer une itération dans array1 et la 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 Programmation orientée objet et 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;
C'est facile avec filtre
Dans cet exemple, nous affectons simplement le nombre, la longueur du tableau filtrée par la clé que vous recherchez.
let array = [{name: "steve", age: 22}, {name: "bob", age: 30}]
let count = array.filter(obj => obj.name === obj.name).length
console.log(count)
plus d'informations sur JS Filiters ici https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
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)
Tableau donné x I.e x = ['boy','man','oldman','scout','pilot'];
Nombre d'occurrences d'un élément 'man'
est
x.length - x.toString().split(',man,').toString().split(',').length ;