Zliczanie wystąpień / częstotliwości elementów tablicy


216

W JavaScript próbuję pobrać początkową tablicę wartości liczbowych i policzyć w niej elementy. Idealnie, wynikiem byłyby dwie nowe tablice, pierwsza określająca każdy unikalny element, a druga zawierająca liczbę wystąpień każdego elementu. Jestem jednak otwarty na sugestie dotyczące formatu danych wyjściowych.

Na przykład, jeśli początkowa tablica to:

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

Następnie powstałyby dwie nowe tablice. Pierwszy zawierałby nazwę każdego unikalnego elementu:

5, 2, 9, 4

Drugi zawierałby liczbę wystąpień tego elementu w początkowej tablicy:

3, 5, 1, 1

Ponieważ liczba 5 występuje trzy razy w początkowej tablicy, liczba 2 występuje pięć razy, a 9 i 4 pojawiają się raz.

Dużo szukałem rozwiązania, ale wydaje się, że nic nie działa, a wszystko, co sam próbowałem, okazało się absurdalnie skomplikowane. Każda pomoc będzie mile widziana!

Dzięki :)


8
Jeśli wszystko, czego potrzebujesz, to zobaczyć, czy wartość pojawia się tylko raz (zamiast dwa lub więcej razy), możesz użyćif (arr.indexOf(value) == arr.lastIndexOf(value))
Rodrigo

1
Możemy to wykorzystać ramda.jsw prosty sposób. 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).lengthpowróciłby, 3aby wskazać, że w tablicy znajdują się piątki „3”.
noobninja

Odpowiedzi:


94

Proszę bardzo:

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 na żywo: http://jsfiddle.net/simevidas/bnACW/

Uwaga

To zmienia kolejność oryginalnej tablicy wejściowej za pomocą Array.sort


24
ma efekt uboczny sortowania tablicy (skutki uboczne są złe), a także sortowanie, O(N log(N))a przyrost elegancji nie jest tego wart
ninjagecko

1
@ninja Którą inną odpowiedź wolisz?
Šime Vidas

Wobec braku ładnego prymitywnego wysokiego poziomu z biblioteki innej firmy, normalnie implementowałbym to tak jak reduceodpowiedź. Już miałem przesłać taką odpowiedź, zanim zobaczyłem, że już istnieje. Niemniej jednak counts[num] = counts[num] ? counts[num]+1 : 1odpowiedź również działa (odpowiednik if(!result[a[i]])result[a[i]]=0odpowiedzi, która jest bardziej elegancka, ale trudniejsza do odczytania); odpowiedzi te można zmodyfikować, aby użyć „ładniejszej” wersji pętli for, być może trzeciej pętli for, ale zignorowałem to, ponieważ standardowe pętle for oparte na indeksie są niestety domyślne.
ninjagecko

2
@ninja Zgadzam się. Te odpowiedzi są lepsze. Niestety nie mogę odrzucić mojej własnej odpowiedzi.
Šime Vidas

W przypadku małych tablic sortowanie w miejscu może być szybsze niż tworzenie tablicy asocjacyjnej.
quant_dev

219

Możesz użyć obiektu do przechowywania wyników:

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

Więc teraz twój obiekt counts może ci powiedzieć, co to jest liczba dla określonej liczby:

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

Jeśli chcesz uzyskać tablicę członków, po prostu użyj keys()funkcji

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

3
Należy zauważyć, że ta Object.keys()funkcja jest obsługiwana tylko w IE9 +, FF4 +, SF5 +, CH6 +, ale Opera jej nie obsługuje. Myślę, że największym ogranicznikiem programu jest IE9 + .
Robert Koritnik

19
Podobnie też mi się podoba counts[num] = (counts[num] || 0) + 1. W ten sposób musisz napisać tylko counts[num]dwa razy zamiast trzech razy w tej jednej linii.
robru

1
To miła odpowiedź. Można to łatwo przekształcić w funkcję, która akceptuje tablicę i zwraca obiekt „counts”.
bitów i

Odnosi się to do konkretnego przykładu w pytaniu, ale ze względu na pracowników Google warto zauważyć, że nie zawsze jest to bezpieczna technika do szerszego zastosowania. Przechowywanie wartości jako kluczy obiektowych do ich liczenia oznacza, że ​​rzutujesz te wartości na ciągi, a następnie zliczasz tę wartość. [5, "5"]powie po prostu, że masz "5"dwa razy. Lub zliczanie instancji różnych przedmiotów po prostu powie ci, że jest ich dużo [object Object]. Itd. Itp.
Jimbo Jonny

Jak mogę następnie odfiltrować zwracany obiekt, aby pokazać mi najwyższą do najniższej lub najniższą do najwyższej liczby na liczbach
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,

Dzięki, bardzo fajne rozwiązanie;) ... i uzyskać tablice „klucz” i „wartość”:const keys = Object.keys(a); const values = Object.values(a);
ncenerar

79

Jeśli używasz podkreślenia lub lodash, jest to najprostsza rzecz do zrobienia:

_.countBy(array);

Tak, że:

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

Jak zauważyli inni, możesz następnie wykonać funkcje _.keys()i _.values()na wyniku, aby uzyskać tylko unikalne liczby i ich wystąpienia. Jednak z mojego doświadczenia wynika, że ​​łatwiej jest sobie poradzić z oryginalnym przedmiotem.


55

Nie używaj dwóch tablic dla wyniku, użyj obiektu:

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

Następnie resultbędzie wyglądać następująco:

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

47

Co powiesz na opcję 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

Ten przykład przekazuje tablicę wejściową do Setkonstruktora, tworząc kolekcję unikalnych wartości. Składnia spread następnie rozszerza te wartości do nowej tablicy, dzięki czemu możemy zadzwonić mapi przełożyć to na dwuwymiarowej tablicy [value, count]parach - czyli o następującej strukturze:

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

Nowa tablica jest następnie przekazywana do Mapkonstruktora, w wyniku czego powstaje iterowalny obiekt:

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

Wspaniałą rzeczą w Mapobiekcie jest to, że zachowuje typy danych - to znaczy, aCount.get(5)że zwróci, 3ale aCount.get("5")zwróci undefined. Pozwala również, aby dowolna wartość / typ działała jako klucz, co oznacza, że ​​to rozwiązanie będzie również działać z tablicą obiektów.


czy masz przypadkiem ulepszoną odpowiedź na to pytanie tylko dla tablicy obiektów? mam problem z próbą zmodyfikowania go dla tablicy obiektów, w której po prostu tworzysz nową tablicę / mapę / zestaw, w której usuwasz duplikaty i dodajesz nową wartość dla obiektu, powiedzmy nazwany „duplicatedCount: value”. udało mi się usunąć duplikaty z mojej tablicy obiektów zagnieżdżonych z tej odpowiedzi stackoverflow.com/a/36744732
Sharon Gur

Setużywa odwołań do obiektów dla unikalności i nie oferuje interfejsu API do porównywania „podobnych” obiektów. Jeśli chcesz zastosować to podejście do takiego zadania, potrzebujesz pośredniej funkcji redukcji, która gwarantuje szereg unikalnych instancji. Nie jest to najbardziej wydajny, ale podam tutaj szybki przykład .
Wysłannik

Dziękuję za odpowiedź! ale właściwie rozwiązałem to trochę inaczej. jeśli widzisz odpowiedź, którą dodałem tutaj stackoverflow.com/a/43211561/4474900 podałem przykład tego, co zrobiłem. działa dobrze, moja sprawa wymagała skomplikowanego porównania. nie wiem jednak o skuteczności mojego rozwiązania
sharon gur

8
Może to wykorzystywać nowe ładne struktury danych, ale ma czas działania w O ( ), podczas gdy istnieje wiele prostych algorytmów, które rozwiązują go w O ( n ).
raphinesse

41

Myślę, że to najprostszy sposób liczenia wystąpień o tej samej wartości w tablicy.

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

9
lub a.filter(value => !value).lengthz nową składnią js
t3chb0t

Nie odpowiada na pytanie.
Ry-

35

Jednoelementowe rozwiązanie ES6. Tak wiele odpowiedzi przy użyciu obiektu jako mapy, ale nie widzę nikogo używającego prawdziwej mapy

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

Użyj, map.keys()aby uzyskać unikalne elementy

Użyj, map.values()aby uzyskać wystąpienia

Użyj, map.entries()aby uzyskać pary [element, częstotliwość]

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


Nowoczesne Javascript dostaje to, co najlepsze ze wszystkich światów
Igniter

30

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
Czy ktoś chciałby to wyjaśnić (prev [curr] = ++ prev [curr] || 1, prev)?
Souljacker

6
Operatora przecinek „oblicza każdy z jej parametrami (od lewej do prawej) i zwraca wartość ostatniego argumentu operacji”, tak więc zwiększa wartość poprzednia [Curr] (lub inicjuje to do 1), a następnie powraca Prev.
ChrisV

ale czy dane wyjściowe są tablicą?
Francesco

20

Jeśli wolisz pojedynczą wkładkę.

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

Edytuj (6/12/2015) : Wyjaśnienie od wewnątrz. countMap to mapa, która odwzorowuje słowo z częstotliwością, którą możemy zobaczyć anonimową funkcję. Zmniejsza to zastosowanie funkcji z argumentami, ponieważ wszystkie elementy tablicy i countMap są przekazywane jako wartość zwracana ostatniego wywołania funkcji. Ostatni parametr ({}) jest domyślną wartością countMap dla pierwszego wywołania funkcji.


1
Powinieneś to wyjaśnić. dzięki temu byłaby to znacznie lepsza odpowiedź, aby ludzie mogli nauczyć się jej używać w innych przypadkach użycia.
Andrew Grothe,

Pojedyncza wkładka, która po prostu usuwa podział linii, który zwykle następuje ;, {i }. ... DOBRZE. Myślę, że z tą definicją jednego linijki możemy napisać Conway's Game of Life jako „oneliner”.
trincot

16

Wersja ES6 powinna znacznie uprościć (kolejne rozwiązanie jednoliniowe)

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 }

Mapa zamiast zwykłego obiektu, który pomaga nam rozróżniać różne typy elementów, w przeciwnym razie wszystkie liczenia są oparte na ciągach znaków


8

Jeśli używasz podkreślenia, możesz wybrać trasę funkcjonalną

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

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

więc twoja pierwsza tablica to

_.keys(results)

a druga tablica to

_.values(results)

większość z nich będzie domyślnie natywnych funkcji javascript, jeśli są one dostępne

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


8

Na podstawie odpowiedzi z @adamse i @pmandell (co upvote), w ES6 można zrobić to w jednym wierszu :

  • Edycja 2017 : Używam, ||aby zmniejszyć rozmiar kodu i uczynić go bardziej czytelnym.

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

));


Może być używany do liczenia znaków :

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

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

));


Byłby bardziej czytelny, gdybyś użył || 0:(r,k)=>{r[k]=(r[k]||0)+1;return r}
12

W JavaScript możesz zrobić wszystko w jednym wierszu.
Ry-

I dlaczego to jest złe, @ Ry-?
ESL

Czasami jest bardziej wyraźny w kilku liniach, inny jest wyraźniejszy w jednej linii. Althoug to kwestia „smaku”.
ESL

Mam na myśli, że „w ES6 możesz to zrobić w jednym wierszu” dotyczy każdej odpowiedzi, a możesz to zrobić w ES5 w jednym wierszu.
Ry-

5

Oto coś lekkiego i łatwego dla oczu ...

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

Edycja: A ponieważ chcesz wszystkie wystąpienia ...

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
Pytanie dotyczy liczby wszystkich elementów.
Ry-

Ok, przegapiłem to. Powinien zostać teraz naprawiony.
ElDoRado1239,

5

Oto jak bym to zrobił z niektórymi najnowszymi funkcjami javascript:

Najpierw zmniejsz tablicę do jednego Mapz poniższych:

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

Korzystając z a Map, tablica początkowa może zawierać dowolny typ obiektu, a liczby będą prawidłowe. Bez a Mapniektóre typy obiektów dają dziwne liczby. Zobacz Mapdokumentację, aby uzyskać więcej informacji na temat różnic.

Można to również zrobić z obiektem, jeśli wszystkie wartości to symbole, liczby lub ciągi znaków:

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

Lub nieco bardziej funkcjonalny w sposób funkcjonalny, bez mutacji, przy użyciu destrukcji i składni rozproszenia obiektów:

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

W tym momencie możesz użyć Map obiektu lub do swoich obliczeń (a mapa jest iterowalna bezpośrednio, w przeciwieństwie do obiektu), lub przekonwertować ją na dwie tablice.

Dla Map:

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

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

Lub dla obiektu:

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

Jeśli nadal chcesz mieć dwie tablice, możesz użyć odpowiedzi w ten sposób ...

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

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

Lub jeśli chcesz, aby liczba unikatowa była liczbą

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

1
es6 / 7 sprawia, że ​​jest to o wiele ładniejsze. Możesz także Mapzamiast tego zredukować do , ponieważ pozwoli to uniknąć rzutowania typowego, jak przy użyciu liczby jako klucza obiektowego (rzutowanie jako ciąg znaków). const answer = array.reduce((a, e) => a.set(e, (a.get(e) || 0) + 1), new Map())Możesz uzyskać answer.keys()klucze, a answer.values()wartości jako tablice. [...answer]da ci dużą tablicę ze wszystkimi kluczami / wartościami jak tablice 2d.
Josh z Qaribou

4

Rozwiązanie ES6 z redukcją (naprawione):

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

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


Nie jestem pewien, jak jedna liczba reprezentuje liczbę każdego odrębnego elementu tablicy, tak jak zadawane pytanie.
Ry-

4

Edycja 2020 : to dość stara odpowiedź (dziewięć lat). Rozszerzenie natywnego prototypezawsze będzie generowało dyskusję . Chociaż myślę, że programista może wybrać własny styl programowania, oto (bardziej nowoczesne) podejście do problemu bez rozszerzania 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; }

Stara (2011) odpowiedź: możesz rozszerzyć Array.prototype, tak jak to:


2

Moje rozwiązanie z 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 do REPL.


2

Rozwiązanie za pomocą mapy o złożoności czasowej 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/


Moje poparcie dla ciebie, to działa jak masło ze złożonością czasu O (n)
Vishal Shetty


1

Korzystając z MAP , możesz mieć 2 tablice wyjściowe: jedna zawierająca wystąpienia, a druga zawiera liczbę wystąpień.

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

Sprawdź kod poniżej.

<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

Spróbuj tego:

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

Rozwiązałem podobny problem w programistach i opracowałem następujące rozwiązanie, które działało dla mnie.

Daje to najwyższą liczbę całkowitą w tablicy, a także samą liczbę całkowitą. Myślę, że można go również zastosować do tablicy ciągów.

Aby prawidłowo posortować ciągi, usuń je function(a, b){return a-b}z sort()części

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

Oto sposób na policzenie wystąpień wewnątrz tablicy obiektów. Umieszcza również zawartość pierwszej tablicy w nowej tablicy, aby posortować wartości, aby kolejność w oryginalnej tablicy nie została zakłócona. Następnie używana jest funkcja rekurencyjna, aby przejść przez każdy element i policzyć właściwość ilości każdego obiektu w tablicy.

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

Bardzo marnotrawstwem jest kopiowanie obiektu za każdym razem. Tworzy kwadratowy najgorszy przypadek, gdy może być liniowy.
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

To pytanie ma ponad 8 lat i wiele, wiele odpowiedzi tak naprawdę nie uwzględnia ES6 i jego licznych zalet.

Być może jeszcze ważniejsze jest zastanowienie się nad konsekwencjami naszego kodu dla odśmiecania pamięci / zarządzania pamięcią, ilekroć tworzymy dodatkowe tablice, tworzymy podwójne lub potrójne kopie tablic, a nawet przekształcamy tablice w obiekty. Są to trywialne obserwacje dla małych zastosowań, ale jeśli skala jest celem długoterminowym, zastanów się nad nimi dokładnie.

Jeśli potrzebujesz tylko „licznika” dla określonych typów danych, a punktem początkowym jest tablica (zakładam, że chcesz mieć uporządkowaną listę i skorzystać z wielu właściwości tablic właściwości i metod), możesz po prostu iterować przez tablicę 1 i wypełnić tablica2 z wartościami i liczbą wystąpień tych wartości znalezionych w tablicy1.

Tak proste jak to.

Przykład prostej klasy SimpleCounter (ES6) do programowania obiektowego i projektowania obiektowego

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;

Trzymanie funkcji w klasie bez powodu nie powoduje, że jest ona zorientowana obiektowo, finalListnie ma powodu, aby być tablicą, a to nie ma przewagi nad prawidłowym wykonaniem.
Ry-

-1

Oto klasyczna oldschoolowa metoda liczenia tablic.

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

Możesz go najpierw posortować, jeśli chcesz uzyskać wynik alfabetyczny, ale jeśli chcesz zachować kolejność wprowadzania danych, spróbuj. Zagnieżdżone pętle mogą być nieco wolniejsze niż niektóre inne metody na tej stronie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.