Sort a Javascript Array by frequency and then filter repeats

前端 未结 8 1756
南笙
南笙 2020-12-13 07:06

What is an elegant way to take a javascript array, order by the frequency of the values, and then filter for uniques?

So,

[\"apples\", \"oranges\", \"o

相关标签:
8条回答
  • 2020-12-13 07:44

    Create a counter of the array's elements using reduce:

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

    Sort the counter object using sort on Object.entries and finally show only keys.

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

    0 讨论(0)
  • 2020-12-13 07:45

    Basic strategy:

    Create an object to use as a hash table to track the frequency of each item in the array to be sorted.

    Create a new array containing the item, frequency pairs.

    Sort this array on frequency in descending order.

    Extract the items from that array.

    Code:

    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; });
     }
    
    0 讨论(0)
  • 2020-12-13 07:51

    Compute the frequency of each item first.

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

    Then create an array from this frequency object which will also remove the duplicates.

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

    Now sort this array in descending order using the frequency map we created earlier.

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

    Here's the entire source (using the newly introduced Array functions in ECMA 5) and combining the de-duplication and frequency map generation steps,

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

    Same as above using the regular array iteration.

    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);
    }
    
    0 讨论(0)
  • 2020-12-13 07:51

    I was actually working on this at the same time - the solution I came up with is pretty much identical to Anurag's.

    However I thought it might be worth sharing as I had a slightly different way of calculating the frequency of occurrences, using the ternary operator and checking if the value has been counted yet in a slightly different way.

    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);
    }
    
    0 讨论(0)
  • 2020-12-13 08:02
    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(","));
    
    0 讨论(0)
  • 2020-12-13 08:03

    for the first step to compute

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

    you can use countBy function of underscroe.js

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

    so frequency object will contain frequency of all unique values, and you can get an unique list by simply calling _.uniq(all), and to sort that unique list by the _.sortBy method of underscore and using your frequency object you can use

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

    -ve sign is used here to sort the list in decending order by means of frequency value as per your requirement.

    You can check the the documentation of http://underscorejs.org/ for further optimization by your own trick :)

    0 讨论(0)
提交回复
热议问题