Het aantal voorkomen/frequentie van array-elementen tellen

In Javascript probeer ik een eerste reeks getalwaarden te nemen en de elementen erin te tellen. Idealiter zou het resultaat twee nieuwe arrays zijn, waarbij de eerste elk uniek element specificeert en de tweede het aantal keren dat elk element voorkomt. Ik sta echter open voor suggesties over het formaat van de uitvoer.

Als de initiële array bijvoorbeeld was:

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

Dan zouden er twee nieuwe arrays worden gemaakt. De eerste zou de naam van elk uniek element bevatten:

5, 2, 9, 4

De tweede zou het aantal keren bevatten dat dat element in de initiële array voorkwam:

3, 5, 1, 1

Omdat het getal 5 drie keer voorkomt in de beginreeks, komt het getal 2 vijf keer voor en komen 9 en 4 beide één keer voor.

Ik heb veel gezocht naar een oplossing, maar niets lijkt te werken, en alles wat ik zelf heb geprobeerd, is uiteindelijk belachelijk complex geworden. Alle hulp wordt op prijs gesteld!

Bedankt 🙂


Antwoord 1, autoriteit 100%

const arr = [2, 2, 5, 2, 2, 2, 4, 5, 5, 9];
function foo (array) {
  let a = [],
    b = [],
    arr = [...array], // clone array so we don't change the original when using .sort()
    prev;
  arr.sort();
  for (let element of arr) {
    if (element !== prev) {
      a.push(element);
      b.push(1);
    }
    else ++b[b.length - 1];
    prev = element;
  }
  return [a, b];
}
const result = foo(arr);
console.log('[' + result[0] + ']','[' + result[1] + ']')
console.log(arr)

2, Autoriteit 246%

U kunt een object gebruiken om de resultaten te houden:

const arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
const counts = {};
for (const num of arr) {
  counts[num] = counts[num] ? counts[num] + 1 : 1;
}
console.log(counts[5], counts[2], counts[9], counts[4]);

3, Autoriteit 109%

const occurrences = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4].reduce(function (acc, curr) {
  return acc[curr] ? ++acc[curr] : acc[curr] = 1, acc
}, {});
console.log(occurrences) // => {2: 5, 4: 1, 5: 3, 9: 1}

4, Autoriteit 82%

Als u Underscore of Lodash gebruikt, is dit het eenvoudigste om te doen:

_.countBy(array);

zodanig dat:

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

Zoals aangegeven door anderen, kunt u vervolgens de _.keys()en _.values()functies op het resultaat om alleen de unieke nummers te krijgen, en hun gebeurtenissen respectievelijk. Maar in mijn ervaring is het originele object veel gemakkelijker om mee om te gaan.


5, Autoriteit 63%

One Line ES6-oplossing. Zoveel antwoorden met object als een kaart, maar ik kan niemand zien met behulp van een echte kaart

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

Gebruik map.keys()om unieke elementen

te krijgen

Gebruik map.values()om de gebeurtenissen

te krijgen

Gebruik map.entries()om de paren [element, frequentie]

te krijgen

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

6, Autoriteit 56%

Gebruik geen twee arrays voor het resultaat, gebruik een object:

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

Dan resultZIKELIJK ZIEN:

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

Antwoord 7, autoriteit 50%

Wat dacht je van een ECMAScript2015-optie.

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

Dit voorbeeld geeft de invoerarray door aan de Setconstructor die een verzameling uniekewaarden maakt. De spread-syntaxisbreidt deze waarden vervolgens uit naar een nieuwe array dus we kunnen Mapaanroepen en dit vertalen in een tweedimensionale array van [value, count]paren – dwz de volgende structuur:

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

De nieuwe array wordt vervolgens doorgegeven aan de Mapconstructor resulterend in een iterableobject:

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

Het mooie van een Map-object is dat het datatypes behoudt – dat wil zeggen dat aCount.get(5)3maar aCount.get("5")retourneert undefined. Het staat ook toe dat elkewaarde/type als sleutel fungeert, wat betekent dat deze oplossing ook werkt met een reeks objecten.


Antwoord 8, autoriteit 43%

Ik denk dat dit de eenvoudigste manier is om exemplaren met dezelfde waarde in een array te tellen.

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

Antwoord 9, autoriteit 32%

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

Antwoord 10, autoriteit 20%

Als je de voorkeur geeft aan een enkele voering.

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

Bewerken (6/12/2015):
De uitleg van binnenuit.
countMap is een kaart die een woord in kaart brengt met zijn frequentie, wat we de anonieme functie kunnen zien. Wat reduce doet, is de functie toepassen met argumenten als alle array-elementen en countMap die wordt doorgegeven als de retourwaarde van de laatste functieaanroep. De laatste parameter ({}) is de standaardwaarde van countMap voor de eerste functieaanroep.


Antwoord 11, autoriteit 18%

ES6-versie zou veel eenvoudiger moeten zijn (nog een éénregelige oplossing)

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 }

Een kaart in plaats van een gewoon object dat ons helpt om verschillende soorten elementen te onderscheiden, of anders zijn alle tellingen gebaseerd op strings


Antwoord 12, autoriteit 14%

Versie van 2021

De elegantere manier is het gebruik van Logical nullish assignment (x ??= y) gecombineerd met Array#reduce()met O(n) tijdcomplexiteit.

Het belangrijkste idee is nog steeds het gebruik van Array#reduce()om te aggregeren met uitvoer als objectom de hoogste prestaties te krijgen (zowel tijd- als ruimtecomplexiteit)in termen van searching& construct bunches of intermediate arrayszoals andere antwoorden.

const arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
const result = arr.reduce((acc, curr) => {
  acc[curr] ??= {[curr]: 0};
  acc[curr][curr]++;
  return acc;
}, {});
console.log(Object.values(result));

Antwoord 13, autoriteit 8%

Gebaseerd op antwoordvan @adamseen @pmandell(waar ik op stem), in ES6jij kan het in één regel:

  • Bewerken 2017: ik gebruik ||om de code te verkleinen en leesbaarder te maken.
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},{})
));

Antwoord 14, autoriteit 7%

Als u onderstrepingstekens gebruikt, kunt u de functionele route volgen

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

dus je eerste array is

_.keys(results)

en de tweede array is

_.values(results)

de meeste hiervan worden standaard ingesteld op native javascript-functies als ze beschikbaar zijn

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


Antwoord 15, autoriteit 6%

Dus hier is hoe ik het zou doen met enkele van de nieuwste JavaScript-functies:

Verklein eerst de array tot een Mapvan de tellingen:

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

Door een Mapte gebruiken, kan uw startarray elk type object bevatten en zullen de tellingen correct zijn. Zonder een Mapzullen sommige soorten objecten je vreemde tellingen geven.
Zie de Map-documentenvoor meer informatie over de verschillen.

Dit kan ook worden gedaan met een object als al uw waarden symbolen, getallen of tekenreeksen zijn:

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

Of iets chiquer op een functionele manier zonder mutatie, met behulp van destructurering en objectspreidingssyntaxis:

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

Op dit punt kunt u de Mapof het object gebruiken voor uw tellingen (en de kaart is direct itereerbaar, in tegenstelling tot een object), of deze converteren naar twee arrays.

Voor de Map:

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

Of voor het object:

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)

Antwoord 16, autoriteit 5%

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

Als je nog steeds tweearrays wilt, dan kun je answerals volgt gebruiken…

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

Of als u wilt dat uniqueNums getallen zijn

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

Antwoord 17, autoriteit 5%

Hier is gewoon iets lichts en gemakkelijks voor de ogen…

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

Bewerken:En aangezien je alle gebeurtenissen wilt…

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

Antwoord 18, autoriteit 3%

Oplossing met behulp van een kaart met O(n)tijdcomplexiteit.

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/


Antwoord 19, autoriteit 2%

Mijn oplossing met 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 naar REPL.


Antwoord 20, autoriteit 2%

Gebruik MAPu kunt 2 arrays in de uitvoer hebben: Een met de voorkomens & de andere bevat het aantal gebeurtenissen.

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)

Antwoord 21, autoriteit 2%

Lodash gebruiken

const values = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
const frequency = _.map(_.groupBy(values), val => ({ value: val[0], frequency: val.length }));
console.log(frequency);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

Antwoord 22, autoriteit 2%

Ik weet dat deze vraag oud is, maar ik realiseerde me dat er te weinig oplossingen zijn waarbij je de count-array krijgt zoals gevraagd met een minimale code, dus hier is de mijne

// The initial array we want to count occurences
var initial = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];  
// The count array asked for
var count = Array.from(new Set(initial)).map(val => initial.filter(v => v === val).length);  
// Outputs [ 3, 5, 1, 1 ]

Bovendien kun je de set uit die initiële array halen met

var set = Array.from(new Set(initial));  
//set = [5, 2, 9, 4]  

Antwoord 23, autoriteit 2%

Een kortere versie gebruikt reduceen tilde (~) operator.

const data = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
function freq(nums) {
  return nums.reduce((acc, curr) => {
    acc[curr] = -~acc[curr];
    return acc;
  }, {});
}
console.log(freq(data));

24

Bekijk de onderstaande code.

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

25

Er is een veel betere en eenvoudige manier waarop we dit kunnen doen met ramda.js.
Codemonster hier

const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
R.countBy(r=> r)(ary)

Counterby Documentation is bij Documentatie


26

Gezien de hieronder geleverde array:

const array = [ 'a', 'b', 'b', 'c', 'c', 'c' ];

U kunt deze eenvoudige one-liner gebruiken om een hash-kaart te genereren die een sleutel koppelt aan het aantal keren dat deze in de array voorkomt:

const hash = Object.fromEntries([ ...array.reduce((map, key) => map.set(key, (map.get(key) || 0) + 1), new Map()) ]);
// { a: 1, b: 2, c: 3 }

Uitgebreid & Uitgelegd:

// first, we use reduce to generate a map with values and the amount of times they appear
const map = array.reduce((map, key) => map.set(key, (map.get(key) || 0) + 1), new Map())
// next, we spread this map into an array
const table = [ ...map ];
// finally, we use Object.fromEntries to generate an object based on this entry table
const result = Object.fromEntries(table);

tegoed aan @corashinavoor de array.reduce-code


Antwoord 27

Probeer dit:

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

Antwoord 28

Ik was een soortgelijk probleem met codewars aan het oplossen en bedacht de volgende oplossing die voor mij werkte.

Dit geeft het hoogste aantal van een geheel getal in een array en ook het gehele getal zelf. Ik denk dat het ook kan worden toegepast op stringarray.

Om Strings correct te sorteren, verwijdert u de function(a, b){return a-b}uit het sort()gedeelte

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

29

Hier is een manier om gebeurtenissen in een reeks objecten te tellen. Het plaatst ook de inhoud van de eerste array in een nieuwe array om de waarden te sorteren, zodat de bestelling in de originele array niet is verstoord. Dan wordt een recursieve functie gebruikt om door elk element te gaan en de hoeveelheid eigenschap van elk object in de array te tellen.

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

Other episodes