web-dev-qa-db-fra.com

Obtenir l'élément avec l'occurrence la plus élevée dans un tableau

Je cherche un moyen élégant de déterminer quel élément a la plus haute occurrence ( mode ) dans un tableau JavaScript. 

Par exemple, dans

['pear', 'Apple', 'orange', 'Apple']

l'élément 'Apple' est l'élément le plus fréquent.

64
vise

Ceci est juste le mode. Voici un rapide, non optimisé Solution. Ce devrait être O (n).

function mode(array)
{
    if(array.length == 0)
        return null;
    var modeMap = {};
    var maxEl = array[0], maxCount = 1;
    for(var i = 0; i < array.length; i++)
    {
        var el = array[i];
        if(modeMap[el] == null)
            modeMap[el] = 1;
        else
            modeMap[el]++;  
        if(modeMap[el] > maxCount)
        {
            maxEl = el;
            maxCount = modeMap[el];
        }
    }
    return maxEl;
}
70
Matthew Flaschen

Il y a eu quelques développements en javascript depuis 2009 - je pensais ajouter une autre option. Je suis moins préoccupé par l'efficacité jusqu'à ce que ce soit réellement un problème, alors ma définition du code {"élégant"}} _ (comme stipulé par l'OP) favorise la lisibilité - ce qui est bien sûr subjectif ...

function mode(arr){
    return arr.sort((a,b) =>
          arr.filter(v => v===a).length
        - arr.filter(v => v===b).length
    ).pop();
}

mode(['pear', 'Apple', 'orange', 'Apple']); // Apple

Dans cet exemple particulier, si deux éléments ou plus de l'ensemble ont des occurrences égales, celui qui apparaît le plus tard dans le tableau sera renvoyé. Il est également intéressant de noter que cela modifiera votre tableau d'origine - ce qui peut être évité si vous le souhaitez avec un appel préalable de Array.slice .


Edit: a mis à jour l'exemple avec quelques ES6grosses flèches parce que 2015 s'est passé et je pense qu'elles sont jolies ... Si vous êtes préoccupé par la compatibilité en amont, vous peut trouver cela dans historique de révision .

42
Emissary

Conformément à la demande George Jempty's demandant à ce que l'algorithme tienne compte des liens, je propose une version modifiée de l'algorithme Matthew Flaschen's.

function modeString(array)
{
    if (array.length == 0)
        return null;

    var modeMap = {},
        maxEl = array[0],
        maxCount = 1;

    for(var i = 0; i < array.length; i++)
    {
        var el = array[i];

        if (modeMap[el] == null)
            modeMap[el] = 1;
        else
            modeMap[el]++;

        if (modeMap[el] > maxCount)
        {
            maxEl = el;
            maxCount = modeMap[el];
        }
        else if (modeMap[el] == maxCount)
        {
            maxEl += '&' + el;
            maxCount = modeMap[el];
        }
    }
    return maxEl;
}

Cela retournera maintenant une chaîne avec le ou les éléments mode délimités par un symbole '&'. Lorsque le résultat est reçu, il peut être divisé sur cet élément '&' et vous avez votre (vos) mode (s). 

Une autre option serait de renvoyer un tableau d’éléments de mode comme ceci:

function modeArray(array)
{
    if (array.length == 0)
        return null;
    var modeMap = {},
        maxCount = 1, 
        modes = [];

    for(var i = 0; i < array.length; i++)
    {
        var el = array[i];

        if (modeMap[el] == null)
            modeMap[el] = 1;
        else
            modeMap[el]++;

        if (modeMap[el] > maxCount)
        {
            modes = [el];
            maxCount = modeMap[el];
        }
        else if (modeMap[el] == maxCount)
        {
            modes.Push(el);
            maxCount = modeMap[el];
        }
    }
    return modes;
}

Dans l'exemple ci-dessus, vous pourrez alors traiter le résultat de la fonction sous la forme d'un tableau de modes.

30
samandmoore
a=['pear', 'Apple', 'orange', 'Apple'];
b={};
max='', maxi=0;
for(let k of a) {
  if(b[k]) b[k]++; else b[k]=1;
  if(maxi < b[k]) { max=k; maxi=b[k] }
}
11
Thinker

Sur la base de la réponse ES6 + de Emissary , vous pouvez utiliser Array.prototype.reduce pour faire votre comparaison (par opposition à trier, éjecter et potentiellement transformer votre tableau), ce qui, à mon avis, semble assez lisse.

const mode = (myArray) =>
  myArray.reduce(
    (a,b,i,arr)=>
     (arr.filter(v=>v===a).length>=arr.filter(v=>v===b).length?a:b),
    null)

La valeur par défaut est null, ce qui ne vous donnera pas toujours une réponse véridique si null est une option possible pour laquelle vous filtrez, peut-être que ce pourrait être un deuxième argument facultatif.

L'inconvénient, à l'instar de diverses autres solutions, est qu'il ne gère pas les «états d'étirage», mais cela pourrait toujours être réalisé avec une fonction de réduction légèrement plus complexe.

8
davidsharp

Essayer une approche déclarative ici. Cette solution construit un objet pour compiler les occurrences de chaque mot. Filtre ensuite l'objet en un tableau en comparant le nombre total d'occurrences de chaque mot à la valeur la plus élevée trouvée dans l'objet.

const arr = ['hello', 'world', 'hello', 'again'];

const tally = (acc, x) => { 

  if (! acc[x]) { 
    acc[x] = 1;
    return acc;
  } 

  acc[x] += 1;
  return acc;
};

const totals = arr.reduce(tally, {});

const keys = Object.keys(totals);

const values = keys.map(x => totals[x]);

const results = keys.filter(x => totals[x] === Math.max(...values));
3
Corey Clark

Voici ma solution à ce problème, mais avec des chiffres et en utilisant la nouvelle fonctionnalité «Set». Ce n’est pas très performant, mais j’ai eu beaucoup de plaisir à écrire cela et il supporte plusieurs valeurs maximales.

const mode = (arr) => [...new Set(arr)]
  .map((value) => [value, arr.filter((v) => v === value).length])
  .sort((a,b) => a[1]-b[1])
  .reverse()
  .filter((value, i, a) => a.indexOf(value) === i)
  .filter((v, i, a) => v[1] === a[0][1])
  .map((v) => v[0])

mode([1,2,3,3]) // [3]
mode([1,1,1,1,2,2,2,2,3,3,3]) // [1,2]

En passant, n'utilisez pas ceci pour la production, ceci est juste une illustration de la façon dont vous pouvez le résoudre avec uniquement les fonctions ES6 et Array.

2
Anjuna5

Comme j'utilise cette fonction en tant que questionnaire pour les interviewers, je publie ma solution:

const highest = arr => (arr || []).reduce( ( acc, el ) => {
  acc.k[el] = acc.k[el] ? acc.k[el] + 1 : 1
  acc.max = acc.max ? acc.max < acc.k[el] ? el : acc.max : el
  return acc  
}, { k:{} }).max

const test = [0,1,2,3,4,2,3,1,0,3,2,2,2,3,3,2]
console.log(highest(test))
2
perusopersonale

Cette solution peut renvoyer plusieurs éléments d'un tableau s'ils se produisent pendant la même heure. par exemple, un tableau arr = [3,4,3,6,4] a deux valeurs de mode, 3 et 6.

Voici la solution,

function find_mode(arr) {
    var max = 0;
    var maxarr = [];
    var counter = [];
    var maxarr = [];

    arr.forEach(function(){
       counter.Push(0);
    });

    for(var i = 0;i<arr.length;i++){
       for(var j=0;j<arr.length;j++){
            if(arr[i]==arr[j])counter[i]++; 
       }
    } 


    max=this.arrayMax(counter);   

    for(var i = 0;i<arr.length;i++){
         if(counter[i]==max)maxarr.Push(arr[i]);
    }

    var unique = maxarr.filter( this.onlyUnique );
    return unique;

  };


function arrayMax(arr) {
      var len = arr.length, max = -Infinity;
      while (len--) {
              if (arr[len] > max) {
              max = arr[len];
              }
      }
  return max;
 };

 function onlyUnique(value, index, self) {
       return self.indexOf(value) === index;
 }
2
Reza

Essayez aussi, cela ne prend pas en compte la version du navigateur.

function mode(arr){
var a = [],b = 0,occurrence;
    for(var i = 0; i < arr.length;i++){
    if(a[arr[i]] != undefined){
        a[arr[i]]++;
    }else{
        a[arr[i]] = 1;
    }
    }
    for(var key in a){
    if(a[key] > b){
        b = a[key];
        occurrence = key;
    }
    }
return occurrence;
}
alert(mode(['segunda','terça','terca','segunda','terça','segunda']));

Veuillez noter que cette fonction renvoie la dernière occurrence dans le tableau quand 2 ou plusieurs entrées apparaissent le même nombre de fois!

1
Marcelo
function mode(arr){
  return arr.reduce(function(counts,key){
    var curCount = (counts[key+''] || 0) + 1;
    counts[key+''] = curCount;
    if (curCount > counts.max) { counts.max = curCount; counts.mode = key; }
    return counts;
  }, {max:0, mode: null}).mode
}
1
Jonah

Temps pour une autre solution:

function getMaxOccurrence(arr) {
    var o = {}, maxCount = 0, maxValue, m;
    for (var i=0, iLen=arr.length; i<iLen; i++) {
        m = arr[i];

        if (!o.hasOwnProperty(m)) {
            o[m] = 0;
        }
        ++o[m];

        if (o[m] > maxCount) {
            maxCount = o[m];
            maxValue = m;
        }
    }
    return maxValue;
}

Si la brièveté compte (ce n'est pas le cas), alors:

function getMaxOccurrence(a) {
    var o = {}, mC = 0, mV, m;
    for (var i=0, iL=a.length; i<iL; i++) {
        m = a[i];
        o.hasOwnProperty(m)? ++o[m] : o[m] = 1;
        if (o[m] > mC) mC = o[m], mV = m;
    }
    return mV;
}

Si des membres inexistants doivent être évités (par exemple un tableau fragmenté), un test supplémentaire de hasOwnProperty est requis:

function getMaxOccurrence(a) {
    var o = {}, mC = 0, mV, m;
    for (var i=0, iL=a.length; i<iL; i++) {
        if (a.hasOwnProperty(i)) {
            m = a[i];
            o.hasOwnProperty(m)? ++o[m] : o[m] = 1;
            if (o[m] > mC) mC = o[m], mV = m;
        }
    }
    return mV;
}

getMaxOccurrence([,,,,,1,1]); // 1

D'autres réponses ici retourneront undefined .

1
RobG
var mode = 0;
var c = 0;
var num = new Array();
var value = 0;
var greatest = 0;
var ct = 0;

Remarque: ct est la longueur du tableau.

function getMode()
{
    for (var i = 0; i < ct; i++)
    {
        value = num[i];
        if (i != ct)
        {
            while (value == num[i + 1])
            {
                c = c + 1;
                i = i + 1;
            }
        }
        if (c > greatest)
        {
            greatest = c;
            mode = value;
        }
        c = 0;
    }
}
1
Kingsley Nnoruka

Voici ma solution: -

function frequent(number){
    var count = 0;
    var sortedNumber = number.sort();
    var start = number[0], item;
    for(var i = 0 ;  i < sortedNumber.length; i++){
      if(start === sortedNumber[i] || sortedNumber[i] === sortedNumber[i+1]){
         item = sortedNumber[i]
      }
    }
    return item
  
}

   console.log( frequent(['pear', 'Apple', 'orange', 'Apple']))

1
Meheret
function mode(array){
    var set = Array.from(new Set(array));
    var counts = set.map(a=>array.filter(b=>b==a).length);
    var indices = counts.map((a,b)=>Math.max(...counts)===a?b:0).filter(b=>b!==0);
    var mode = indices.map(a=>set[a]);
    return mode;
}
0
ido klein
var cats = ['Tom','Fluffy','Tom','Bella','Chloe','Tom','Chloe'];
var counts = {};
var compare = 0;
var mostFrequent;
(function(array){
   for(var i = 0, len = array.length; i < len; i++){
       var Word = array[i];

       if(counts[Word] === undefined){
           counts[Word] = 1;
       }else{
           counts[Word] = counts[Word] + 1;
       }
       if(counts[Word] > compare){
             compare = counts[Word];
             mostFrequent = cats[i];
       }
    }
  return mostFrequent;
})(cats);
0
Rubin bhandari
const mode = (str) => {
  return str
    .split(' ')
    .reduce((data, key) => {
      let counter = data.map[key] + 1 || 1
      data.map[key] = counter

      if (counter > data.counter) {
        data.counter = counter
        data.mode = key
      }

      return data
    }, {
      counter: 0,
      mode: null,
      map: {}
    })
    .mode
}

console.log(mode('the t-rex is the greatest of them all'))
0
Pablo

Voici la version moderne qui utilise des cartes intégrées (elle fonctionne donc plus que ce qui peut être converti en chaînes uniques):

'use strict';

const histogram = iterable => {
    const result = new Map();

    for (const x of iterable) {
        result.set(x, (result.get(x) || 0) + 1);
    }

    return result;
};

const mostCommon = iterable => {
    let maxCount = 0;
    let maxKey;

    for (const [key, count] of histogram(iterable)) {
        if (count > maxCount) {
            maxCount = count;
            maxKey = key;
        }
    }

    return maxKey;
};

console.log(mostCommon(['pear', 'Apple', 'orange', 'Apple']));

0
Ry-

Vous pouvez essayer ceci:

 // using splice()   
 // get the element with the highest occurence in an array
    function mc(a) {
      var us = [], l;
      // find all the unique elements in the array
      a.forEach(function (v) {
        if (us.indexOf(v) === -1) {
          us.Push(v);
        }
      });
      l = us.length;
      while (true) {
        for (var i = 0; i < l; i ++) {
          if (a.indexOf(us[i]) === -1) {
            continue;
          } else if (a.indexOf(us[i]) != -1 && a.length > 1) {
            // just delete it once at a time
            a.splice(a.indexOf(us[i]), 1);
          } else {
            // default to last one
            return a[0];
          }
        }
      }
    }

// using string.match method
function su(a) {
    var s = a.join(),
            uelms = [],
            r = {},
            l,
            i,
            m;

    a.forEach(function (v) {
        if (uelms.indexOf(v) === -1) {
            uelms.Push(v);
        }
    });

    l = uelms.length;

    // use match to calculate occurance times
    for (i = 0; i < l; i ++) {
        r[uelms[i]] = s.match(new RegExp(uelms[i], 'g')).length;
    }

    m = uelms[0];
    for (var p in r) {
        if (r[p] > r[m]) {
            m = p;
        } else {
            continue;
        }
    }

    return m;
}
0
void4096

Voici mon chemin. J'essaie de regrouper le poing de données. 

const _ = require("underscore")

var test  = [ 1, 1, 2, 1 ];
var groupResult = _.groupBy(test, (e)=> e);

Le groupeResult devrait être 

{
  1: [1, 1, 1]
  2: [2] 
}

Puis trouver la propriété qui a le plus long tableau

function findMax(groupResult){
   var maxArr = []
   var max;
   for(var item in groupResult){
     if(!max) { 
        max = { value:item, count: groupResult[item].length } ; 
        maxArr.Push(max); 
        continue;
     }
     if(max.count < groupResult[item].length){ 
        maxArr = [];
        max = { value:item, count: groupResult[item].length }
        maxArr.Push(max)
     } else if(max === groupResult[item].length)
        maxArr.Push({ value:item, count: groupResult[item].length })
   }
   return maxArr;
}

Le code complet ressemble à

const _ = require("underscore")

var test  = [ 1, 1, 2, 1 ];
var groupResult= _.groupBy(test, (e)=> e);
console.log(findMax(groupResult)[0].value);

function findMax(groupResult){
   var maxArr = []
   var max;
   for(var item in groupResult){
     if(!max) { 
        max = { value:item, count: groupResult[item].length } ; 
        maxArr.Push(max); 
        continue;
     }
     if(max.count < groupResult[item].length){ 
        maxArr = [];
        max = { value:item, count: groupResult[item].length }
        maxArr.Push(max)
     } else if(max === groupResult[item].length)
        maxArr.Push({ value:item, count: groupResult[item].length })
   }
   return maxArr;
}
0
Andy Lai
var array = [1, 3, 6, 6, 6, 6, 7, 7, 12, 12, 17],
    c = {}, // counters
    s = []; // sortable array

for (var i=0; i<array.length; i++) {
    c[array[i]] = c[array[i]] || 0; // initialize
    c[array[i]]++;
} // count occurrences

for (var key in c) {
    s.Push([key, c[key]])
} // build sortable array from counters

s.sort(function(a, b) {return b[1]-a[1];});

var firstMode = s[0][0];
console.log(firstMode);
0
David Rosson

Cette fonction est une fonction générique pour chaque type d’information. Il compte l'occurrence des éléments puis retourne un tableau avec le maximum d'éléments présents 

function mode () {
  var arr = [].slice.call(arguments);
  if ((args.length == 1) && (typeof args[0] === "object")) {
    args = args[0].mode();
  }

  var obj = {};
  for(var i = 0; i < arr.length; i++) {
    if(obj[arr[i]] === undefined) obj[arr[i]] = 1;
    else obj[arr[i]]++;
  }

  var max = 0;
  for (w in obj) {
    if (obj[w] > max) max = obj[w];
  }

  ret_val = [];
  for (w in obj) {
    if (obj[w] == max) ret_val.Push(w);
  }

  return ret_val;
}
0

Avec ES6, vous pouvez chaîner la méthode comme ceci:

    function findMostFrequent(arr) {
      return arr
        .reduce((acc, cur, ind, arr) => {
          if (arr.indexOf(cur) === ind) {
            return [...acc, [cur, 1]];
          } else {
            acc[acc.indexOf(acc.find(e => e[0] === cur))] = [
              cur,
              acc[acc.indexOf(acc.find(e => e[0] === cur))][1] + 1
            ];
            return acc;
          }
        }, [])
        .sort((a, b) => b[1] - a[1])
        .filter((cur, ind, arr) => cur[1] === arr[0][1])
        .map(cur => cur[0]);
    }
    
    console.log(findMostFrequent(['pear', 'Apple', 'orange', 'Apple']));
    console.log(findMostFrequent(['pear', 'Apple', 'orange', 'Apple', 'pear']));

Si deux éléments ont la même occurrence, les deux seront renvoyés. Et cela fonctionne avec n'importe quel type d'élément.

0
Vu Huu Cuong
// O(n)
var arr = [1, 2, 3, 2, 3, 3, 5, 6];
var duplicates = {};
max = '';
maxi = 0;
arr.forEach((el) => {
    duplicates[el] = duplicates[el] + 1 || 1;
  if (maxi < duplicates[el]) {
    max = el;
    maxi = duplicates[el];
  }
});
console.log(max);
0
indrajeet

Vous pouvez le résoudre en O(n) complexité

var arr = [1,3,54,56,6,6,1,6];
var obj = {};

/* first convert the array in to object with unique elements and number of times each element is repeated */
for(var i = 0; i < arr.length; i++)
{
   var x = arr[i];
   if(!obj[x])
     obj[x] = 1;
   else 
     obj[x]++;
}

console.log(obj);//just for reference

/* now traverse the object to get the element */
var index = 0;
var max = 0;

for(var obIndex in obj)
{
  if(obj[obIndex] > max)
  {
    max = obj[obIndex];
    index = obIndex;
  }
}
console.log(index+" got maximum time repeated, with "+ max +" times" );

Il suffit de copier et coller dans la console chrome pour exécuter le code ci-dessus.

0
Sandeep Gantait

Je suppose que vous avez deux approches. Les deux ont des avantages.

Triez ensuite Compter ou Boucle et utilisez une table de hachage pour effectuer le comptage à votre place. 

La hashtable est agréable, car une fois le traitement terminé, vous disposez également de tous les éléments distincts. Si vous aviez cependant des millions d'éléments, la table de hachage pourrait utiliser beaucoup de mémoire si le taux de duplication était faible. L'approche de tri, puis de comptage aurait une empreinte mémoire beaucoup plus contrôlable.

0
Steve Sheldon
function mode(){
  var input = $("input").val().split(",");
  var mode = [];
  var m = [];
  var p = [];
    for(var x = 0;x< input.length;x++){
      if(m.indexOf(input[x])==-1){
        m[m.length]=input[x];
    }}
  for(var x = 0; x< m.length;x++){
    p[x]=0;
    for(var y = 0; y<input.length;y++){
      if(input[y]==m[x]){
      p[x]++; 
 }}}
 for(var x = 0;x< p.length;x++){
   if(p[x] ==(Math.max.apply(null, p))){
     mode.Push(m[x]);
 }} 
$("#output").text(mode);}
0
Harris Mowbray