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

Jack W.
źródło
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

Šime Vidas
źródło
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"]
typ
źródło
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}
adamse
źródło
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.

radicand
źródło
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
}
mu jest za krótki
źródło
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.

Emisariusz
źródło
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
Dmytro Kozłowski
źródło
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()])

corashina
źródło
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))

Vlad Bezden
źródło
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.

rjalfa
źródło
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

William Leung
źródło
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/

jhnstn
źródło
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},{})

));

ESL
źródło
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;
}
ElDoRado1239
źródło
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)
Garrett Motzner
źródło
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];
SoEzPz
źródło
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

Thomas Gotwig
źródło
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:

KooiInc
źródło
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.

Michał
źródło
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/

Sardorjon Vakkosov
źródło
Moje poparcie dla ciebie, to działa jak masło ze złożonością czasu O (n)
Vishal Shetty
1

Jest o wiele lepszy i łatwy sposób, w jaki możemy to zrobić za pomocą ramda.js. Przykładowy kod tutaj

const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]; R.countBy(r=> r)(ary) Dokumentacja countBy znajduje się w dokumentacji

Eshwar Prasad Yaddanapudi
źródło
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)

Melchia
źródło
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>
Wouter van Nifterick
źródło
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;
}
Aamir Afridi
źródło
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;
}
Varun Upadhyay
źródło
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)));
}
nate_js
źródło
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]};
      }
    }, {})
}
José Salgado
źródło
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]);
}
Dilraj Singh
źródło
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;
rags2riches
źródło
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.

MangoPapa7
źródło