【问题标题】:Sort a Javascript Array by frequency and then filter repeats按频率对 Javascript 数组进行排序,然后过滤重复
【发布时间】:2011-04-04 12:23:06
【问题描述】:

获取 javascript 数组、按值的频率排序、然后过滤唯一值的优雅方法是什么?

所以,

["apples", "oranges", "oranges", "oranges", "bananas", "bananas", "oranges"]

变成

["oranges, "bananas", "apples"]

【问题讨论】:

    标签: javascript arrays sorting


    【解决方案1】:

    首先计算每个项目的频率。

    {
        apples: 1,
        oranges: 4,
        bananas: 2
    }
    

    然后从这个频率对象创建一个数组,该数组也将删除重复项。

    ["apples", "oranges", "bananas"]
    

    现在使用我们之前创建的频率图对这个数组进行降序排序。

    function compareFrequency(a, b) {
        return frequency[b] - frequency[a];
    }
    
    array.sort(compareFrequency);
    

    这是整个源代码(使用 ECMA 5 中新引入的Array functions)并结合了重复数据删除和频率图生成步骤,

    function sortByFrequency(array) {
        var frequency = {};
    
        array.forEach(function(value) { frequency[value] = 0; });
    
        var uniques = array.filter(function(value) {
            return ++frequency[value] == 1;
        });
    
        return uniques.sort(function(a, b) {
            return frequency[b] - frequency[a];
        });
    }
    

    使用常规数组迭代与上述相同。

    function sortByFrequencyAndRemoveDuplicates(array) {
        var frequency = {}, value;
    
        // compute frequencies of each value
        for(var i = 0; i < array.length; i++) {
            value = array[i];
            if(value in frequency) {
                frequency[value]++;
            }
            else {
                frequency[value] = 1;
            }
        }
    
        // make array from the frequency object to de-duplicate
        var uniques = [];
        for(value in frequency) {
            uniques.push(value);
        }
    
        // sort the uniques array in descending order by frequency
        function compareFrequency(a, b) {
            return frequency[b] - frequency[a];
        }
    
        return uniques.sort(compareFrequency);
    }
    

    【讨论】:

      【解决方案2】:

      //从最频繁到最不频繁返回

      Array.prototype.byCount= function(){
          var itm, a= [], L= this.length, o= {};
          for(var i= 0; i<L; i++){
              itm= this[i];
              if(!itm) continue;
              if(o[itm]== undefined) o[itm]= 1;
              else ++o[itm];
          }
          for(var p in o) a[a.length]= p;
          return a.sort(function(a, b){
              return o[b]-o[a];
          });
      }
      

      //测试

      var A= ["apples","oranges","oranges","oranges","bananas","bananas","oranges"];
      A.byCount()
      

      /* 返回值:(数组) 橘子、香蕉、苹果 */

      【讨论】:

        【解决方案3】:

        我实际上同时也在研究这个——我想出的解决方案与 Anurag 的几乎相同。

        但是我认为它可能值得分享,因为我计算出现频率的方法略有不同,使用三元运算符并检查值是否已以稍微不同的方式计算。

        function sortByFrequencyAndFilter(myArray)
        {
            var newArray = [];
            var freq = {};
        
            //Count Frequency of Occurances
            var i=myArray.length-1;
            for (var i;i>-1;i--)
            {
                var value = myArray[i];
                freq[value]==null?freq[value]=1:freq[value]++;
            }
        
            //Create Array of Filtered Values
            for (var value in freq)
            {
                newArray.push(value);
            }
        
            //Define Sort Function and Return Sorted Results
            function compareFreq(a,b)
            {
                return freq[b]-freq[a];
            }
        
            return newArray.sort(compareFreq);
        }
        

        【讨论】:

        • 我用来计算出现频率的循环检查一个常数值并反向循环遍历数组。这在大型阵列上也会执行得更快。
        【解决方案4】:

        让我在 ES6 中放一个最小的代码来获取唯一值(和频率)。

        var arr = ["apples", "oranges", "oranges", "oranges", "bananas", "bananas", "oranges"];
        console.log([...new Set(arr)])

        它也适用于对象数组以聚合一些属性。

        var arr = [{"fruit":"apples"}, {"fruit":"oranges"}, {"fruit":"oranges"}, {"fruit":"oranges"}, {"fruit":"bananas"}, {"fruit":"bananas"}, {"fruit":"oranges"}];
        console.log(arr.reduce((x,y)=>{if(x[y.fruit]) {x[y.fruit]++;return x;} else {var z={};z[y.fruit]=1;return Object.assign(x,z);}},{}))

        【讨论】:

        • 这如何给你频率?它只是巩固
        【解决方案5】:

        基本策略:

        创建一个对象用作哈希表来跟踪要排序的数组中每个项目的频率。

        创建一个包含项目、频率对的新数组。

        按频率降序对该数组进行排序。

        从该数组中提取项目。

        代码:

        function descendingUniqueSort(toBeSorted) {
            var hash = new Object();
            toBeSorted.forEach(function (element, index, array) { 
                                   if (hash[element] == undefined) {
                                       hash[element] = 1;
                                   }
                                   else {
                                       hash[element] +=1;
                                   }});
            var itemCounts = new Array();
            for (var key in hash) {
               var itemCount = new Object();
               itemCount.key = key;
               itemCount.count = hash[key];
               itemCounts.push(itemCount);
            }
            itemCounts.sort(function(a,b) { if(a.count<b.count) return 1; 
                else if (a.count>b.count) return -1; else return 0;});
        
            return itemCounts.map(function(itemCount) { return itemCount.key; });
         }
        

        【讨论】:

          【解决方案6】:
          var arr = ["apples", "oranges", "oranges", "oranges", "bananas", "bananas", "oranges"].sort();
          var freq = {};
          for (var s in arr) freq[s] = freq[s] ? freq[s] + 1 : 0;
          arr.sort(function(a, b) { return freq[a] > freq[b] ? -1 : 1; });
          for (var i = arr.length - 1; i > 0; i--) if (arr[i] == arr[i - 1]) arr.splice(i,1);
          alert(arr.join(","));
          

          【讨论】:

            【解决方案7】:

            计算的第一步

            {
                oranges: 4,
                bananas: 2,
                apples: 1
            }
            

            你可以使用 underscroe.js 的 countBy 函数

            var all=["apples", "oranges", "oranges", "oranges", "bananas", "bananas", "oranges"];
            var frequency=_.countBy(all,function(each){return each});
            

            所以frequency 对象将包含所有唯一值的频率,您只需调用_.uniq(all) 即可获得唯一列表,并通过下划线的_.sortBy 方法和使用您的frequency 对该唯一列表进行排序您可以使用的对象

            _.sortBy(_.uniq(all),function(frequencyKey){return -frequency[frequencyKey]});
            

            -ve 符号在这里用于根据您的要求按频率值按降序对列表进行排序。

            您可以查看http://underscorejs.org/ 的文档以通过您自己的技巧进一步优化:)

            【讨论】:

              【解决方案8】:

              使用reduce 创建数组元素的计数器:

              arr.reduce(
                (counter, key) => {counter[key] = 1 + counter[key] || 1; return counter}, 
                {}
              );
              

              Object.entries 上使用sort 对计数器对象进行排序,最后只显示键。

              const arr = ["apples", "oranges", "oranges", "oranges",
                "bananas", "bananas", "oranges"
              ];
              
              // create a counter object on array
              let counter = arr.reduce(
                (counter, key) => {
                  counter[key] = 1 + counter[key] || 1;
                  return counter
                }, {});
              console.log(counter);
              // {"apples": 1, "oranges": 4, "bananas": 2}
              
              // sort counter by values (compare position 1 entries)
              // the result is an array
              let sorted_counter = Object.entries(counter).sort((a, b) => b[1] - a[1]);
              console.log(sorted_counter);
              // [["oranges", 4], ["bananas", 2], ["apples", 1]]
              
              // show only keys of the sorted array
              console.log(sorted_counter.map(x => x[0]));
              // ["oranges", "bananas", "apples"]

              【讨论】:

                最近更新 更多