Conteggio delle occorrenze / frequenza degli elementi dell'array


218

In Javascript, sto cercando di prendere una matrice iniziale di valori numerici e contare gli elementi al suo interno. Idealmente, il risultato sarebbe due nuove matrici, la prima che specifica ciascun elemento univoco e la seconda contenente il numero di volte in cui si verifica ciascun elemento. Tuttavia, sono aperto a suggerimenti sul formato dell'output.

Ad esempio, se l'array iniziale era:

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

Quindi verranno creati due nuovi array. Il primo conterrebbe il nome di ciascun elemento univoco:

5, 2, 9, 4

Il secondo conterrebbe il numero di volte in cui l'elemento si è verificato nella matrice iniziale:

3, 5, 1, 1

Poiché il numero 5 viene visualizzato tre volte nella matrice iniziale, il numero 2 viene visualizzato cinque volte e 9 e 4 vengono visualizzati entrambi una volta.

Ho cercato molto una soluzione, ma nulla sembra funzionare e tutto ciò che ho provato da solo ha finito per essere ridicolmente complesso. Qualsiasi aiuto sarebbe apprezzato!

Grazie :)


8
Se tutto ciò che serve fosse vedere se un valore appare solo una volta (invece di due o più volte), potresti usareif (arr.indexOf(value) == arr.lastIndexOf(value))
Rodrigo

1
Possiamo usarlo ramda.jsper ottenere questo in modo semplice. 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).lengthritornerebbe 3per indicare che ci sono "3" nell'array.
noobninja,

Risposte:


94

Ecco qui:

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

Demo live: http://jsfiddle.net/simevidas/bnACW/

Nota

Questo cambia l'ordine dell'array di input originale usando Array.sort


24
ha l'effetto collaterale di ordinare l'array (gli effetti collaterali sono cattivi), anche l'ordinamento lo è O(N log(N))e il guadagno di eleganza non ne vale la pena
ninjagecko,

1
@ninja Quale altra risposta preferisci?
Šime Vidas,

In assenza di una bella primitiva di alto livello da una libreria di terze parti, normalmente implementerei questo come la reducerisposta. Stavo per inviare una risposta del genere prima di vederla già esistente. Tuttavia, anche la counts[num] = counts[num] ? counts[num]+1 : 1risposta funziona (equivalente alla if(!result[a[i]])result[a[i]]=0risposta, che è più elegante ma meno facile da leggere); queste risposte possono essere modificate per usare una versione "più bella" del ciclo for, forse un for-loop di terze parti, ma ho ignorato che dal momento che i for-loop standard basati su indice sono purtroppo quelli predefiniti.
ninjagecko,

2
@ninja Sono d'accordo. Quelle risposte sono migliori. Purtroppo non riesco a non accettare la mia risposta.
Šime Vidas,

Per gli array di piccole dimensioni, l'ordinamento sul posto può essere più rapido della creazione di un array associativo.
quant_dev,

219

Puoi usare un oggetto per contenere i risultati:

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

Quindi, ora l'oggetto conteggi può dirti qual è il conteggio per un determinato numero:

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

Se vuoi ottenere un array di membri, usa semplicemente le keys()funzioni

keys(counts); // returns ["5", "2", "9", "4"]

3
Va sottolineato che tale Object.keys()funzione è supportata solo in IE9 +, FF4 +, SF5 +, CH6 + ma Opera non la supporta. Penso che il più grande tappo dello spettacolo qui sia IE9 + .
Robert Koritnik,

19
Allo stesso modo, mi piace anche counts[num] = (counts[num] || 0) + 1. In questo modo devi solo scrivere counts[num]due volte anziché tre volte su quell'unica riga lì.
Robru,

1
Questa è una bella risposta Questo viene facilmente estratto in una funzione che accetta un array e restituisce un oggetto "conteggi".
bitsand

Questo è vero per l'esempio specifico nella domanda, ma per il bene dei googler vale la pena sottolineare che questa non è sempre una tecnica sicura per un uso più ampio. Memorizzare i valori come chiavi dell'oggetto per contarli significa che stai lanciando quei valori nelle stringhe e poi contando quel valore. [5, "5"]dirò semplicemente che hai "5"due volte. O contare esempi di oggetti diversi ti dirà che ce ne sono molti [object Object]. Ecc. Ecc.
Jimbo Jonny il

Come potrei quindi filtrare l'oggetto restituito per mostrarmi il conteggio dal più alto al più basso o dal più basso al più alto su un numero
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}

39
acc[curr] ? acc[curr]++ : acc[curr] = 1;
pmandell,

Grazie, soluzione molto bella;) ... e per ottenere le matrici "chiave" e "valore":const keys = Object.keys(a); const values = Object.values(a);
ncenerar

79

Se si utilizza il trattino basso o lodash, questa è la cosa più semplice da fare:

_.countBy(array);

Tale che:

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

Come sottolineato da altri, è quindi possibile eseguire le funzioni _.keys()e _.values()sul risultato per ottenere rispettivamente solo i numeri univoci e le loro occorrenze. Ma nella mia esperienza, l'oggetto originale è molto più facile da gestire.


55

Non utilizzare due matrici per il risultato, utilizzare un oggetto:

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

Quindi resultsarà simile a:

{
    2: 5,
    4: 1,
    5: 3,
    9: 1
}

48

Che ne dici di un'opzione 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

Questo esempio passa l'array di input al Setcostruttore creando una raccolta di valori univoci . La sintassi di diffusione quindi espande questi valori in un nuovo array in modo che possiamo chiamarlo mape tradurlo in un array bidimensionale di [value, count]coppie, ovvero la seguente struttura:

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

Il nuovo array viene quindi passato al Mapcostruttore risultante in un oggetto iterabile :

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

La cosa grandiosa di un Mapoggetto è che conserva i tipi di dati - vale a dire aCount.get(5)che tornerà 3ma aCount.get("5")tornerà undefined. Inoltre, consente a qualsiasi valore / tipo di agire come chiave, il che significa che questa soluzione funzionerà anche con una matrice di oggetti.


hai per caso una risposta migliorata solo per un array di oggetti? sto riscontrando problemi nel tentativo di modificarlo per un array di oggetti, in cui è sufficiente creare un nuovo array / mappa / set in cui rimuovere i duplicati e aggiungere un nuovo valore per l'oggetto, diciamo "duplicatedCount: value". sono riuscito a rimuovere i duplicati nel mio array di oggetti nidificati da questa risposta stackoverflow.com/a/36744732
sharon gur

Setutilizza riferimenti a oggetti per unicità e non offre API per il confronto di oggetti "simili" . Se si desidera utilizzare questo approccio per tale attività, è necessaria una funzione di riduzione intermedia che garantisca una serie di istanze uniche. Non è il più efficiente, ma ho messo insieme un rapido esempio qui .
Emissario,

Grazie per la risposta! ma in realtà l'ho risolto in modo leggermente diverso. se vedi la risposta che ho aggiunto qui stackoverflow.com/a/43211561/4474900 ho dato un esempio di ciò che ho fatto. funziona bene, il mio caso aveva un oggetto complesso da confrontare. non so dell'efficienza della mia soluzione però
Sharon Gur,

8
Questo potrebbe usare nuove strutture dati piacevoli ma ha un runtime in O ( ) mentre ci sono molti semplici algoritmi che lo risolvono in O ( n ).
raphinesse

41

Penso che questo sia il modo più semplice per contare le occorrenze con lo stesso valore nell'array.

var a = [true, false, false, false];
a.filter(function(value){
    return value === false;
}).length

9
o a.filter(value => !value).lengthcon la nuova sintassi js
t3chb0t

Non risponde alla domanda
Ry-

36

Soluzione ES6 a una riga. Così tante risposte usando l'oggetto come una mappa ma non riesco a vedere nessuno che utilizza una vera mappa

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

Uso map.keys() per ottenere elementi unici

Uso map.values() per ottenere le occorrenze

Utilizzare map.entries()per ottenere le coppie [elemento, frequenza]

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()])


Javascript moderno ottiene il meglio da tutti i mondi
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))


4
Qualcuno vorrebbe spiegare questo (prev [curr] = ++ prev [curr] || 1, prev)?
Souljacker

6
L' operatore virgola "valuta ciascuno dei suoi operandi (da sinistra a destra) e restituisce il valore dell'ultimo operando", quindi questo aumenta il valore di prev [curr] (o lo inizializza a 1), quindi restituisce prev.
ChrisV,

ma l'output è un array?
Francesco,

20

Se preferisci una singola fodera.

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

Modifica (6/12/2015) : la spiegazione dall'interno verso l'esterno. countMap è una mappa che mappa una parola con la sua frequenza, di cui possiamo vedere la funzione anonima. Ciò che riduce è applicare la funzione con argomenti poiché tutti gli elementi dell'array e countMap vengono passati come valore di ritorno dell'ultima chiamata di funzione. L'ultimo parametro ({}) è il valore predefinito di countMap per la prima chiamata di funzione.


1
Dovresti spiegarlo. questo renderebbe una risposta molto migliore in modo che le persone possano imparare a usarlo in altri casi d'uso.
Andrew Grothe,

Un singolo liner che rimuove solo l'interruzione di linea che di solito seguirà ;, {e }. ... OK. Penso che con quella definizione di one liner possiamo scrivere Conway's Game of Life come "oneliner".
trincot

16

La versione ES6 dovrebbe essere molto semplificata (un'altra soluzione a una riga)

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 }

Una mappa invece di un semplice oggetto ci aiuta a distinguere diversi tipi di elementi, oppure tutti i conteggi sono basati su stringhe


8

Se stai usando il trattino basso puoi seguire il percorso funzionale

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

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

quindi il tuo primo array è

_.keys(results)

e il secondo array è

_.values(results)

la maggior parte di questo passerà automaticamente alle funzioni javascript native se sono disponibili

demo: http://jsfiddle.net/dAaUU/


8

Sulla base della risposta di @adamse e @pmandell (che ho votato), in ES6 puoi farlo in una riga :

  • Modifica del 2017 : utilizzo ||per ridurre le dimensioni del codice e renderlo più leggibile.

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},{})

));


Può essere usato per contare i personaggi :

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

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

));


Sarebbe più leggibile se || 0(r,k)=>{r[k]=(r[k]||0)+1;return r}
usassi

Puoi fare qualsiasi cosa in una riga in JavaScript.
Ry-

E perché è una brutta cosa, @ Ry-?
ESL,

A volte è più chiaro in più righe, l'altro è più chiaro in una riga. Althoug è una questione di "gusto".
ESL,

Voglio dire "in ES6 puoi farlo in una riga" si applica a ogni risposta, e puoi farlo anche in ES5 in una riga.
Ry-

5

Ecco solo qualcosa di leggero e facile per gli occhi ...

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

Modifica: E poiché vuoi tutte le occorrenze ...

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

1
La domanda ha richiesto il conteggio di tutti gli elementi.
Ry-

Ok, l'ho perso. Ora dovrebbe essere risolto.
ElDoRado1239,

5

Quindi ecco come lo farei con alcune delle più recenti funzionalità javascript:

Innanzitutto, ridurre l'array a uno Mapdei conteggi:

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

Usando a Map, l'array iniziale può contenere qualsiasi tipo di oggetto e i conteggi saranno corretti. Senza un Map, alcuni tipi di oggetti ti daranno strani conteggi. Vedi i Mapdocumenti per maggiori informazioni sulle differenze.

Questo potrebbe essere fatto anche con un oggetto se tutti i tuoi valori sono simboli, numeri o stringhe:

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

O leggermente più elaborato in modo funzionale senza mutazione, usando la sintassi destrutturante e diffusa:

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

A questo punto, puoi usare il Map oggetto o per i tuoi conteggi (e la mappa è direttamente iterabile, a differenza di un oggetto), oppure convertirlo in due array.

Per il Map:

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

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

O per l'oggetto:

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)

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

Se desideri ancora due array, puoi utilizzare la risposta in questo modo ...

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

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

O se vuoi che uniqueNums sia un numero

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

1
es6 / 7 rende tutto molto più bello. Puoi anche ridurre a Map, invece, poiché eviterà il typecasting che usa un numero come chiave dell'oggetto (casting come stringa). const answer = array.reduce((a, e) => a.set(e, (a.get(e) || 0) + 1), new Map()).Puoi ottenere answer.keys()le chiavi e answer.values()i valori come matrici. [...answer]ti darà un grande array con tutte le chiavi / i valori come array 2d.
Josh da Qaribou il

4

Soluzione ES6 con riduzione (fissa):

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

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


Non sono sicuro di come un numero rappresenti i conteggi di ciascun elemento matrice distinto come la domanda posta.
Ry-

4

Modifica 2020 : questa è una risposta piuttosto vecchia (nove anni). L'estensione del nativo prototypegenererà sempre discussioni . Anche se penso che il programmatore sia libero di scegliere il proprio stile di programmazione, ecco un approccio (più moderno) al problema senza estendere 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; }

La vecchia risposta (2011): potresti estendere in Array.prototypequesto modo:


2

La mia soluzione con 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)

Link a REPL.


2

Soluzione che utilizza una mappa con complessità temporale 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;
}

Demo: http://jsfiddle.net/simevidas/bnACW/


Il mio voto per te, funziona come il burro con la complessità del tempo O (n)
Vishal Shetty


1

Utilizzando MAP è possibile avere 2 array nell'output: uno contenente le occorrenze e l'altro contiene il numero di occorrenze.

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)


0

Dai un'occhiata al codice qui sotto.

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

0

Prova questo:

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

0

Stavo risolvendo un problema simile su codewars e ho ideato la seguente soluzione che ha funzionato per me.

Ciò fornisce il conteggio più alto di un numero intero in un array e anche l'intero stesso. Penso che possa essere applicato anche all'array di stringhe.

Per ordinare correttamente le stringhe, rimuovere l' function(a, b){return a-b}interno della sort()porzione

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

Ecco un modo per contare le occorrenze all'interno di una matrice di oggetti. Inoltre, inserisce i contenuti del primo array all'interno di un nuovo array per ordinare i valori in modo che l'ordine nell'array originale non venga interrotto. Quindi viene utilizzata una funzione ricorsiva per esaminare ciascun elemento e contare la proprietà quantità di ciascun oggetto all'interno dell'array.

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
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]};
      }
    }, {})
}

Estremamente dispendioso copiare l'oggetto ogni volta. Crea un caso peggiore quadratico quando potrebbe essere lineare.
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]);
}

0

Questa domanda ha più di 8 anni e molte, molte risposte non tengono davvero conto dell'ES6 e dei suoi numerosi vantaggi.

Forse è ancora più importante pensare alle conseguenze del nostro codice per la garbage collection / gestione della memoria ogni volta che creiamo array aggiuntivi, facciamo copie doppie o triple di array o addirittura convertiamo array in oggetti. Queste sono osservazioni banali per piccole applicazioni, ma se la scala è un obiettivo a lungo termine, pensaci attentamente.

Se hai solo bisogno di un "contatore" per tipi di dati specifici e il punto di partenza è un array (suppongo che tu voglia quindi un elenco ordinato e trarre vantaggio dalle numerose proprietà e metodi che gli array offrono), puoi semplicemente iterare attraverso array1 e popolare array2 con i valori e il numero di occorrenze per questi valori trovati in array1.

Così semplice.

Esempio di semplice classe SimpleCounter (ES6) per la programmazione orientata agli oggetti e la progettazione orientata agli oggetti

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;

Attaccare una funzione in una classe senza motivo non la rende orientata agli oggetti, finalListnon ha motivo di essere un array e questo non ha vantaggi rispetto a farlo correttamente.
Ry-

-1

Ecco un metodo classico di vecchia scuola per contare le matrici.

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

Puoi ordinarlo prima se vuoi un risultato alfabetico, ma se vuoi preservare l'ordine in cui sono stati inseriti i dati, allora prova. I loop nidificati potrebbero essere leggermente più lenti di alcuni degli altri metodi in questa pagina.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.