Luke
Luke

Reputation: 5708

Dedup array and sort array by most frequent occurrence (with LoDash)

Say I have an array that goes something like:

fruit_basket = ['apple', 'orange', 'banana', 'pear', 'banana']

I want to make an array fruits that consists of the fruits found in fruit basket, sorted in order of most frequently occurring fruit. (If there are ties I don't care about ordering.)

So one valid value for fruits is:

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

What's the most concise way to achieve this using LoDash? I don't care about run time performance.

Upvotes: 2

Views: 2068

Answers (4)

Paulo R.
Paulo R.

Reputation: 15609

Here's my take on this.

It doesn't use lodash as the question asks for. It's a vanilla alternative. I feel this could be valuable to people who land here from Google and don't want to use lodash (that's how I got here, at least).

const orderByCountAndDedupe = arr => {
    const counts = new Map();

    arr.forEach( item => {
        if ( !counts.has(item) ) {
            counts.set(item, 1);
        } else {
            counts.set(item, counts.get(item)+1);
        }
    });

    return (
        Array.from(counts)
            .sort( (a, b) => b[1] - a[1])
            .map( ([originalItem, count]) => originalItem)
    );
 };

Upvotes: 1

Lukáš Havrlant
Lukáš Havrlant

Reputation: 4414

You can count occurences using _.countBy and then use it in _.sortBy:

var counter = _.countBy(fruit_basket)
var result  = _(fruit_basket).uniq().sortBy(fruit => counter[fruit]).reverse().value()

Upvotes: 0

adeneo
adeneo

Reputation: 318302

First you'd count the occurences

var x = _.chain(fruit_basket).countBy(); // {apple: 1, orange: 1, banana: 2, pear: 1}

Then you'd pair them and sort by the number of occurences, using reverse to get the largest number first

var y = x.toPairs().sortBy(1).reverse(); //[["banana",2],["pear",1],["orange",1],["apple",1]]

Then you'd just map back the keys, and get the value as an array

var arr = y.map(0).value(); // ['banana', 'orange', 'apple', 'pear'] 

All chained together, it looks like

var arr = _.chain(fruit_basket).countBy().toPairs().sortBy(1).reverse().map(0).value();

Without loDash, something like this would do it

var fruit_basket = ['apple', 'orange', 'banana', 'pear', 'banana'];

var o = {};
fruit_basket.forEach(function(item) {
    item in o ? o[item] += 1 : o[item] = 1;
});
var arr = Object.keys(o).sort(function(a, b) {
    return o[a] < o[b];
});

Upvotes: 4

guest271314
guest271314

Reputation: 1

An approach using for loop Array.prototype.splice()

var fruit_basket = ['apple', 'orange', 'banana', 'pear', 'banana'];
var res = [];
for (var i = 0; i < fruit_basket.length; i++) {
  var index = res.indexOf(fruit_basket[i]);
  // if current item does not exist in `res`
  // push current item to `res`
  if (index == -1) {
    res.push(fruit_basket[i])
  } else {
    // else remove current item , set current item at index `0` of `res`
    res.splice(index, 1);
    res.splice(0, 0, fruit_basket[i])
  }
}

console.log(res)

Upvotes: 0

Related Questions