Zählen der Vorkommen / Häufigkeit von Array-Elementen


215

In Javascript versuche ich, ein anfängliches Array von Zahlenwerten zu verwenden und die darin enthaltenen Elemente zu zählen. Im Idealfall wären das Ergebnis zwei neue Arrays, von denen das erste jedes eindeutige Element angibt und das zweite die Häufigkeit enthält, mit der jedes Element auftritt. Ich bin jedoch offen für Vorschläge zum Format der Ausgabe.

Zum Beispiel, wenn das ursprüngliche Array war:

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

Dann würden zwei neue Arrays erstellt. Das erste würde den Namen jedes einzelnen Elements enthalten:

5, 2, 9, 4

Die zweite würde die Häufigkeit enthalten, mit der dieses Element im ursprünglichen Array vorkam:

3, 5, 1, 1

Da die Zahl 5 im anfänglichen Array dreimal vorkommt, kommt die Zahl 2 fünfmal vor und 9 und 4 erscheinen beide einmal.

Ich habe viel nach einer Lösung gesucht, aber nichts scheint zu funktionieren, und alles, was ich selbst ausprobiert habe, ist lächerlich komplex geworden. Jede Hilfe wäre dankbar!

Vielen Dank :)


8
Wenn Sie nur sehen müssen, ob ein Wert nur einmal (statt zweimal oder mehrmals) angezeigt wird, können Sieif (arr.indexOf(value) == arr.lastIndexOf(value))
Rodrigo

1
Wir können ramda.jsdies auf einfache Weise erreichen. 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).lengthwürde zurückkehren, 3um anzuzeigen, dass das Array '3' fünf enthält.
Noobninja

Antworten:


94

Bitte schön:

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

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

Hinweis

Dies ändert die Reihenfolge des ursprünglichen Eingabearrays mit Array.sort


24
hat Nebeneffekt beim Sortieren des Arrays (Nebenwirkungen sind schlecht), auch das Sortieren ist O(N log(N))und der
Eleganzgewinn

1
@ninja Welche andere Antwort bevorzugen Sie?
Šime Vidas

In Abwesenheit eines netten High-Level-Grundelements aus einer Drittanbieter-Bibliothek würde ich dies normalerweise wie das implementieren reduce Antwort . Ich wollte gerade eine solche Antwort einreichen, bevor ich sah, dass sie bereits existierte. Trotzdem counts[num] = counts[num] ? counts[num]+1 : 1funktioniert die Antwort auch (entspricht der if(!result[a[i]])result[a[i]]=0Antwort, die eleganter, aber weniger leicht zu lesen ist); Diese Antworten können geändert werden, um eine "schönere" Version der for-Schleife zu verwenden, möglicherweise eine for-Schleife eines Drittanbieters, aber ich habe das irgendwie ignoriert, da die standardmäßigen indexbasierten for-Schleifen leider die Standardeinstellung sind.
Ninjagecko

2
@ Ninja Ich stimme zu. Diese Antworten sind besser. Leider kann ich meine eigene Antwort nicht ablehnen.
Šime Vidas

Bei kleinen Arrays kann das Sortieren schneller erfolgen als das Erstellen eines assoziativen Arrays.
quant_dev

219

Sie können ein Objekt verwenden, um die Ergebnisse zu speichern:

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

Jetzt kann Ihr Zählobjekt Ihnen sagen, wie hoch die Zählung für eine bestimmte Zahl ist:

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

Wenn Sie eine Reihe von Mitgliedern erhalten möchten, verwenden Sie einfach die keys()Funktionen

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

3
Es sollte darauf hingewiesen werden, dass diese Object.keys()Funktion nur in IE9 +, FF4 +, SF5 +, CH6 + unterstützt wird, Opera jedoch nicht. Ich denke, der größte Show-Stopper hier ist IE9 + .
Robert Koritnik

19
Ebenso mag ich auch counts[num] = (counts[num] || 0) + 1. Auf diese Weise müssen Sie dort nur counts[num]zweimal statt dreimal in diese eine Zeile schreiben .
Robru

1
Das ist eine schöne Antwort. Dies lässt sich leicht in eine Funktion abstrahieren, die ein Array akzeptiert und ein 'count'-Objekt zurückgibt.
Bitsand

Dies gilt für das spezifische Beispiel in der Frage, aber für Googler ist darauf hinzuweisen, dass dies nicht immer eine sichere Technik für eine breitere Verwendung ist. Wenn Sie die Werte als Objektschlüssel speichern, um sie zu zählen, werden diese Werte in Zeichenfolgen umgewandelt und anschließend gezählt. [5, "5"]Ich werde einfach sagen, dass du "5"zwei Mal hast . Oder das Zählen von Instanzen verschiedener Objekte sagt Ihnen nur, dass es viele gibt [object Object]. Usw. usw.
Jimbo Jonny

Wie könnte ich dann das zurückgegebene Objekt filtern, um die höchste bis niedrigste oder die niedrigste bis höchste Anzahl einer Zahl
anzuzeigen

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

Danke, sehr schöne Lösung;) ... und um die Arrays "key" und "value" zu erhalten:const keys = Object.keys(a); const values = Object.values(a);
ncenerar

79

Wenn Sie Unterstrich oder Lodash verwenden, ist dies am einfachsten:

_.countBy(array);

So dass:

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

Wie von anderen hervorgehoben, können Sie dann die Funktionen _.keys()und _.values()für das Ergebnis ausführen , um nur die eindeutigen Zahlen und deren Vorkommen zu erhalten. Aber meiner Erfahrung nach ist das ursprüngliche Objekt viel einfacher zu handhaben.


55

Verwenden Sie keine zwei Arrays für das Ergebnis, sondern ein Objekt:

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

Dann resultsieht es so aus:

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

47

Wie wäre es mit einer ECMAScript2015-Option.

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

In diesem Beispiel wird das Eingabearray an den SetKonstruktor übergeben, wodurch eine Sammlung eindeutiger Werte erstellt wird. Die Spread-Syntax erweitert diese Werte dann zu einem neuen Array, sodass wir dies aufrufen mapund in ein zweidimensionales Array von [value, count]Paaren übersetzen können - dh die folgende Struktur:

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

Das neue Array wird dann an den MapKonstruktor übergeben, was zu einem iterierbaren Objekt führt:

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

Das Tolle an einem MapObjekt ist, dass es Datentypen beibehält - das heißt, es aCount.get(5)wird zurückkehren, 3aber aCount.get("5")zurückkehren undefined. Außerdem kann jeder Wert / Typ als Schlüssel fungieren, was bedeutet, dass diese Lösung auch mit einer Reihe von Objekten funktioniert.


Haben Sie zufällig eine verbesserte Antwort darauf nur für ein Objektarray? Ich habe Probleme beim Versuch, es für ein Objektarray zu ändern, bei dem Sie einfach ein neues Array / eine neue Map / einen neuen Satz erstellen, in dem Sie Duplikate entfernen und einen neuen Wert für das Objekt hinzufügen, beispielsweise "duplicatedCount: value". Ich habe es geschafft, Duplikate in meinem verschachtelten Objekt-Array aus dieser Antwort zu entfernen. stackoverflow.com/a/36744732
sharon gur

Setverwendet Objektreferenzen zur Eindeutigkeit und bietet keine API zum Vergleich von "ähnlichen" Objekten. Wenn Sie diesen Ansatz für eine solche Aufgabe verwenden möchten, benötigen Sie eine Zwischenreduktionsfunktion, die eine Reihe eindeutiger Instanzen garantiert. Es ist nicht das effizienteste, aber ich habe hier ein kurzes Beispiel zusammengestellt .
Abgesandter

Danke für die Antwort! aber ich habe es tatsächlich ein bisschen anders gelöst. Wenn Sie die Antwort sehen können, die ich hier hinzugefügt habe stackoverflow.com/a/43211561/4474900 Ich habe ein Beispiel gegeben, was ich getan habe. es funktioniert gut, mein Fall hatte ein komplexes Objekt, das verglichen werden musste. Ich weiß nicht über die Effizienz meiner Lösung
Bescheid

8
Dies könnte nette neue Datenstrukturen verwenden, hat aber Laufzeit in O ( ), während es hier viele einfache Algorithmen gibt, die es in O ( n ) lösen .
Raphinesse

41

Ich denke, dies ist der einfachste Weg, um Vorkommen mit demselben Wert im Array zu zählen.

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

9
oder a.filter(value => !value).lengthmit der neuen js-Syntax
t3chb0t

Beantwortet die Frage nicht.
Ry-

34

Einzeilige ES6-Lösung. So viele Antworten mit Objekt als Karte, aber ich kann niemanden sehen, der eine tatsächliche Karte verwendet

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

Verwenden map.keys() diese , um eindeutige Elemente zu erhalten

Verwenden map.values() diese , um die Vorkommen abzurufen

Verwenden Sie map.entries(), um die Paare [Element, Frequenz] zu erhalten.

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


Modernes Javascript holt das Beste aus allen Welten
Igniter

29

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


3
Würde es jemandem etwas ausmachen, dies zu erklären (prev [curr] = ++ prev [curr] || 1, prev)?
Souljacker

5
Der Kommaoperator "wertet jeden seiner Operanden aus (von links nach rechts) und gibt den Wert des letzten Operanden zurück", erhöht also den Wert von prev [curr] (oder initialisiert ihn auf 1) und gibt dann prev zurück.
ChrisV

Aber ist die Ausgabe ein Array?
Francesco

20

Wenn Sie einen einzelnen Liner bevorzugen.

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

Bearbeiten (6/12/2015) : Die Erklärung von innen nach außen. countMap ist eine Karte, die ein Wort mit seiner Häufigkeit abbildet, wobei wir die anonyme Funktion sehen können. Reduzieren wendet die Funktion mit Argumenten an, da alle Array-Elemente und countMap als Rückgabewert des letzten Funktionsaufrufs übergeben werden. Der letzte Parameter ({}) ist der Standardwert von countMap für den ersten Funktionsaufruf.


1
Sie sollten dies erklären. Das würde es zu einer viel besseren Antwort machen, damit die Leute lernen können, wie man es in anderen Anwendungsfällen verwendet.
Andrew Grothe

Ein einzelner Liner, der nur den Zeilenumbruch entfernt, der normalerweise folgt ;, {und }. ... OK. Ich denke, mit dieser Definition eines Einzeilers können wir Conways Spiel des Lebens als "Oneliner" schreiben.
Trincot

16

Die ES6-Version sollte viel einfacher sein (eine weitere einzeilige Lösung).

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 }

Eine Karte anstelle eines einfachen Objekts hilft uns, verschiedene Arten von Elementen zu unterscheiden, oder alle Zählungen basieren auf Zeichenfolgen


8

Wenn Sie einen Unterstrich verwenden, können Sie den funktionalen Weg gehen

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

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

Ihr erstes Array ist also

_.keys(results)

und das zweite Array ist

_.values(results)

Das meiste davon verwendet standardmäßig native Javascript-Funktionen, sofern diese verfügbar sind

Demo: http://jsfiddle.net/dAaUU/


8

Basierend auf der Antwort von @adamse und @pmandell (die ich positiv bewertet habe) können Sie dies in ES6 in einer Zeile tun :

  • 2017 bearbeiten : Ich verwende ||, um die Codegröße zu reduzieren und sie lesbarer zu machen.

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

));


Es kann verwendet werden, um Zeichen zu zählen :

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

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

));


Es wäre besser lesbar, wenn Sie verwenden würden || 0:(r,k)=>{r[k]=(r[k]||0)+1;return r}
12Me21

Sie können in JavaScript alles in einer Zeile tun.
Ry-

Und warum ist es eine schlechte Sache, @ Ry-?
ESL

Manchmal ist es in mehreren Zeilen klarer, in einer Zeile ist es klarer. Trotzdem ist es eine Frage des "Geschmacks".
ESL

Ich meine, "in ES6 können Sie es in einer Zeile tun" gilt für jede Antwort, und Sie können dies auch in ES5 in einer Zeile tun.
Ry-

5

Hier ist nur etwas Leichtes und Leichtes für die Augen ...

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

Edit: Und da willst du alle Vorkommen ...

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
Bei der Frage wurden alle Elemente gezählt.
Ry-

Ok, das habe ich verpasst. Sollte jetzt behoben sein.
ElDoRado1239

5

So würde ich es mit einigen der neuesten Javascript-Funktionen machen:

Reduzieren Sie zunächst das Array auf einen Mapder folgenden Werte:

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

Wenn Sie a verwenden Map, kann Ihr Startarray einen beliebigen Objekttyp enthalten, und die Anzahl ist korrekt. Ohne a Mapgeben Ihnen einige Objekttypen seltsame Zählungen. Weitere Informationen zu den Unterschieden finden Sie in den MapDokumenten .

Dies kann auch mit einem Objekt erfolgen, wenn alle Ihre Werte Symbole, Zahlen oder Zeichenfolgen sind:

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

Oder auf funktionale Weise ohne Mutation etwas schicker, unter Verwendung von Destrukturierungs- und Objektverbreitungssyntax:

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

Zu diesem Zeitpunkt können Sie das MapObjekt oder für Ihre Zählungen verwenden (und die Karte ist im Gegensatz zu einem Objekt direkt iterierbar) oder in zwei Arrays konvertieren.

Für die Map:

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

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

Oder für das Objekt:

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

Wenn Sie immer noch zwei Arrays möchten , können Sie eine Antwort wie diese verwenden ...

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

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

Oder wenn Sie möchten, dass uniqueNums Zahlen sind

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

1
es6 / 7 macht das alles viel schöner. Möglicherweise möchten Sie Mapstattdessen auch auf a reduzieren , da dadurch die Typumwandlung vermieden wird, die durch die Verwendung einer Zahl als Objektschlüssel (Casting als Zeichenfolge) erfolgt. const answer = array.reduce((a, e) => a.set(e, (a.get(e) || 0) + 1), new Map())Sie können answer.keys()für die Schlüssel und answer.values()für die Werte als Arrays erhalten. [...answer]Sie erhalten ein großes Array mit allen Schlüsseln / Werten als 2D-Arrays.
Josh aus Qaribou

4

ES6-Lösung mit Reduktion (fest):

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

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


Nicht sicher, wie eine Zahl die Anzahl der einzelnen Array-Elemente wie die gestellte Frage darstellt.
Ry-

4

Edit 2020 : Dies ist eine ziemlich alte Antwort (neun Jahre). Das Erweitern des Native prototypeführt immer zu Diskussionen . Obwohl ich denke, dass die Programmiererin frei ist, ihren eigenen Programmierstil zu wählen, ist hier ein (modernerer) Ansatz für das Problem, ohne es zu erweitern 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; }

Die alte (2011) Antwort: Sie könnten so erweitern Array.prototype:


2

Meine Lösung mit 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 zu REPL.


2

Lösung unter Verwendung einer Karte mit O (n) Zeitkomplexität.

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/


Mein Upvote an Sie, dies funktioniert wie Butter mit O (n) Zeitkomplexität
Vishal Shetty


1

Mit MAP können Sie zwei Arrays in der Ausgabe haben: Eines enthält die Vorkommen und das andere enthält die Anzahl der Vorkommen.

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

Überprüfen Sie den Code unten.

<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

Versuche dies:

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

Ich habe ein ähnliches Problem mit Codewars gelöst und die folgende Lösung entwickelt, die für mich funktioniert hat.

Dies gibt die höchste Anzahl einer Ganzzahl in einem Array und auch die Ganzzahl selbst an. Ich denke, es kann auch auf String-Arrays angewendet werden.

Um die Saiten richtig zu sortieren, entfernen Sie die function(a, b){return a-b}aus dem Inneren des sort()Teils

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

Hier ist eine Möglichkeit, Vorkommen in einem Array von Objekten zu zählen. Außerdem wird der Inhalt des ersten Arrays in einem neuen Array platziert, um die Werte so zu sortieren, dass die Reihenfolge im ursprünglichen Array nicht unterbrochen wird. Dann wird eine rekursive Funktion verwendet, um jedes Element zu durchlaufen und die Mengeneigenschaft jedes Objekts innerhalb des Arrays zu zählen.

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

Es ist äußerst verschwenderisch, das Objekt jedes Mal zu kopieren. Erzeugt einen quadratischen Worst-Case, wenn er linear sein könnte.
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

Diese Frage ist mehr als 8 Jahre alt und viele, viele Antworten berücksichtigen ES6 und seine zahlreichen Vorteile nicht wirklich .

Vielleicht ist es noch wichtiger, über die Konsequenzen unseres Codes für die Speicherbereinigung / Speicherverwaltung nachzudenken, wenn wir zusätzliche Arrays erstellen, doppelte oder dreifache Kopien von Arrays erstellen oder sogar Arrays in Objekte konvertieren. Dies sind triviale Beobachtungen für kleine Anwendungen, aber wenn Skalierung ein langfristiges Ziel ist, denken Sie gründlich darüber nach.

Wenn Sie nur einen "Zähler" für bestimmte Datentypen benötigen und der Ausgangspunkt ein Array ist (ich nehme an, Sie möchten daher eine geordnete Liste und die vielen Eigenschaften und Methoden nutzen, die Arrays bieten), können Sie einfach Array1 durchlaufen und füllen Array2 mit den Werten und der Anzahl der Vorkommen für diese Werte in Array1.

So einfach ist das.

Beispiel einer einfachen Klasse SimpleCounter (ES6) für objektorientierte Programmierung und objektorientiertes Design

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;

Wenn eine Funktion ohne Grund in eine Klasse eingefügt wird, finalListist sie nicht objektorientiert, hat keinen Grund, ein Array zu sein, und dies hat keine Vorteile gegenüber einer ordnungsgemäßen Ausführung.
Ry-

-1

Hier ist eine klassische Old-School-Methode zum Zählen von Arrays.

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

Sie können es zuerst sortieren, wenn Sie ein alphabetisches Ergebnis wünschen. Wenn Sie jedoch die Reihenfolge beibehalten möchten, in der die Daten eingegeben wurden, versuchen Sie es. Verschachtelte Schleifen sind möglicherweise etwas langsamer als einige der anderen Methoden auf dieser Seite.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.