代码之家  ›  专栏  ›  技术社区  ›  vise

获取数组中出现次数最多的元素

  •  65
  • vise  · 技术社区  · 16 年前

    我正在寻找一种优雅的方法来确定哪个元素的出现率最高( mode )在一个javascript数组中。

    例如,在

    ['pear', 'apple', 'orange', 'apple']
    

    这个 'apple' 元素是最常见的元素。

    25 回复  |  直到 6 年前
        1
  •  70
  •   Matthew Flaschen    16 年前

    这就是模式。这里有一个 快速,非优化 解决方案。应该是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;
    }
    
        2
  •  42
  •   Community CDub    8 年前

    自2009年以来,Javascript已经有了一些发展——我想我会添加另一个选项。我不太关心效率,直到它成为一个问题,所以我的定义 “雅致” 代码(如操作规程所规定的)有利于可读性——这当然是主观的……

    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
    

    在这个特定的例子中,如果集合中的两个或多个元素的出现次数相等,那么将返回数组中出现最新的元素。同样值得指出的是,它将修改原始数组-如果您希望使用 Array.slice 提前打电话。


    编辑: 用一些 ES6 fat arrows 因为 二千零一十五 我觉得他们看起来很漂亮…如果您关心向后兼容性,可以在 revision history .

        3
  •  30
  •   noɥʇʎԀʎzɐɹƆ    7 年前

    按照 George Jempty's 请求对TIES进行算法说明,我建议修改版本 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;
    }
    

    这将返回一个字符串,其中模式元素由 '&' 符号。当接收到结果时,可以将其拆分为 “&” 元素和您的模式。

    另一个选项是返回模式元素数组,如下所示:

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

    在上面的示例中,您将能够以模式数组的形式处理函数的结果。

        4
  •  11
  •   Kamil Kiełczewski    7 年前
    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] }
    }
    
        5
  •  8
  •   davidsharp    8 年前

    基于 使者 的ES6+答案,您可以使用 Array.prototype.reduce 进行比较(而不是排序、弹出和可能改变数组),我认为这看起来相当巧妙。

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

    我将默认为空,如果空是您正在筛选的一个可能选项,那么它不会总是给您一个真实的响应,也许这是一个可选的第二个参数。

    与其他各种解决方案一样,缺点是它不处理“draw states”,但使用稍微复杂一点的reduce函数仍然可以实现这一点。

        6
  •  3
  •   Corey Clark    8 年前

    在这里尝试声明性方法。这个解决方案构建一个对象来统计每个单词的出现次数。然后,通过将每个单词的总出现次数与在对象中找到的最高值进行比较,将对象筛选为一个数组。

    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));
    
        7
  •  2
  •   Reza    9 年前

    如果数组中的多个元素同时出现,则此解决方案可以返回它们。例如,数组arr=[3,4,3,6,4]有两个模式值,即3和6。

    这是解决方案,

    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;
     }
    
        8
  •  2
  •   Anjuna5    8 年前

    这是我解决这个问题的方法,但是使用数字和新的“集合”功能。它的性能不是很好,但是我写这个肯定很有趣,它支持多个最大值。

    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]
    

    顺便说一句,不要将其用于生产,这只是说明如何仅使用ES6和数组函数来解决问题。

        9
  •  2
  •   perusopersonale    7 年前

    当我将此功能用作面试官的测验时,我发布了我的解决方案:

    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))
    
        10
  •  1
  •   Peter Mortensen icecrime    13 年前
    var mode = 0;
    var c = 0;
    var num = new Array();
    var value = 0;
    var greatest = 0;
    var ct = 0;
    

    注:CT为阵列长度。

    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;
        }
    }
    
        11
  •  1
  •   RobG    11 年前

    其他解决方案的时间:

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

    如果简洁很重要(不重要),那么:

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

    如果要避免不存在的成员(例如稀疏数组),则需要 哈桑特性 需要进行测试:

    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
    

    这里的其他答案将返回 未定义 .

        12
  •  1
  •   Jonah    9 年前
    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
    }
    
        13
  •  1
  •   Meheret    8 年前

    这是我的解决方案:

    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']))
        14
  •  1
  •   msanford    7 年前

    也试试看,这不考虑浏览器版本。

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

    请注意,此函数返回数组中最新出现的 当两个或多个条目出现相同次数时!

        15
  •  0
  •   Steve Sheldon    14 年前

    我想你有两种方法。两者都有优势。

    排序、计数或循环并使用哈希表为您进行计数。

    哈希表很好,因为一旦处理完成,您还拥有所有不同的元素。但是,如果您有数百万个项目,那么如果复制率很低,哈希表最终可能会占用大量内存。排序然后计数的方法将有一个更可控的内存占用。

        16
  •  0
  •   David Rosson    10 年前
    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);
    
        17
  •  0
  •   void4096    9 年前

    您可以尝试以下操作:

     // 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;
    }
    
        18
  •  0
  •   Sandeep Gantait    9 年前

    你可以在O(N)复杂性中解决它

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

    只需复制并粘贴到chrome控制台中即可运行上述代码。

        19
  •  0
  •   רונן ברברמן    8 年前

    此函数是每种信息类型的通用函数。它计算元素的出现次数,然后返回具有最大发生次数的元素的数组。

    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;
    }
    
        20
  •  0
  •   Pablo    8 年前
    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'))
    
        21
  •  0
  •   Harris Mowbray    8 年前
    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);}
    
        22
  •  0
  •   ido klein    7 年前
    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;
    }
    
        23
  •  0
  •   Andy Lai    6 年前

    这是我的路。我试着先将数据分组。

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

    GroupResult应为

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

    然后查找数组最长的属性

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

    完整的代码看起来像

    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;
    }
    
        24
  •  0
  •   Rubin bhandari    6 年前
    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);
    
        25
  •  0
  •   Cuong Vu    6 年前

    使用ES6,您可以这样链接方法:

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

    如果两个元素的出现次数相同,则返回这两个元素。它适用于任何类型的元素。