1

I'm using the following function to get the most frequent item of an array:

Array.prototype.array_most_frequent = function()  {
  var m=0, mf=0;
  for (var i=0; i<this.length; i++) {
          for (var j=i; j<this.length; j++)
          {
            if (this[i] == this[j]) m++;
            if (mf<m) {mf=m; item = this[i]; }
          }
          m=0;
  }
  return item;
}

Works fine - but how to get the rarest item of an array?

For example var array=[2,1,2,5,5] should return '1'.

Is there an easy way to the least frequent item of my array?

Thanks in advance.

  • Your function doesn't actually work. – SLaks Oct 24 '17 at 18:44
  • 1
    Modifying built-in prototypes is bad practice. – SLaks Oct 24 '17 at 18:45
  • Javascript identifiers should be lowerCamelCase. – SLaks Oct 24 '17 at 18:45
  • You can use a dictionary. For every item, create an entry in the dictionary with value = 1 or if it exists already, increase it by 1. At the end, iterate through the dictionary and keep track of the running low using a tuple (start with 0, for first item set your low to that and set which number it was, then keep checking if the next item is lower). If you can have multiple lows just keep a list and clear out the list every time you run into a new low. – bhow Oct 24 '17 at 18:46

7 Answers7

4

An ES6 solution that creates a Map of occurrences using Array#reduce. Then spread the map to get the entries, and reduce the entry to the entry with the smallest number of occurrences:

const array=[2,1,2,5,5];

const result = [...array.reduce((r, n) => // create a map of occurrences
    r.set(n, (r.get(n) || 0) + 1), new Map()
  )]
  .reduce((r, v) => v[1] < r[1] ? v : r)[0]; // get the the item that appear less times


console.log(result);
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
1

You could use a hash to track occurrences then return min value of its values.

function leastFrequent(arr) {
    var dict = {};
    arr.forEach(function(el) {
        if (!dict[el]) dict[el] = 0;
        dict[el]++;
    });
    return Math.min.apply(null, Object.values(dict));
}

// ES6+
const leastFrequent = arr => {
    const dict = {};
    arr.forEach(function(el) {
        if (!dict[el]) dict[el] = 0;
        dict[el]++;
    });
    return Math.min(...Object.values(dict));
}

Cheers

Andrew Senner
  • 2,479
  • 1
  • 18
  • 24
1

The short solution could be this, if the sort function don't mutate the array, even passing the parameter by a function. (If passing for a class constructor this will not happen.)

Modifying a little bit... this.

const arr = [2, 1, 2, 5, 5];
const result = arr.sort((a,b) =>
          arr.filter(v => v===b).length
        - arr.filter(v => v===a).length
    ).pop();

console.log(result)

But sometimes mutability is not desired and that could be an inconvenient, so follow in bellow a solution with no mutability:

Based in a this solution, that just count and add for a object, the name of repeated value and how much times it happen. After that, just take the least one, search in object by the least value to return the name of key that least is repeated.

const arr = [2, 1, 2, 5, 5];
const reducedOnes = arr.reduce((acc, val) => ({...acc, [val]: (acc[val] || 0) + 1}), {});
const leastFrequency = Math.min(...Object.values(reducedOnes));
const leastItem = Object.keys(reducedOnes).find(el=>reducedOnes[el]===leastFrequency);

console.log(leastItem);
Julio C.
  • 55
  • 5
  • Did you intend to post the same answer twice? It would be a good idea to delete one. – Jason Aller Aug 02 '20 at 00:57
  • I didn't post the same solution, at least this is not showing to me. I just post two different solutions. Some times mutability is not desired. I posted a initial one with mutability and after I saw that could be an inconvenient, so I find another solution and post again. – Julio C. Aug 02 '20 at 15:44
  • Ah, then merging them into a single answer and adding more explanation would be a good idea. – Jason Aller Aug 02 '20 at 15:58
  • Great! Done! Better? – Julio C. Aug 03 '20 at 01:18
0
var arr = [2,1,2,5,5];
var frequencyMap = {};
for(var i=0; i<arr.length; i++) {
   frequencyMap[arr[i]] = frequencyMap[arr[i]] || 0;
   frequencyMap[arr[i]]++;
}
var maxValue = 0,maxFreq=0, minValue=NUMBER.MAX_INTEGER,minFreq=0;
for (var key in frequencyMap) {
    if (frequencyMap[key] > maxFreq){
       maxFreq  = frequencyMap[key];
       maxValue = key;
    }else if (frequencyMap[key] < minFreq){
       minFreq  = frequencyMap[key];
       minValue = key;
    }
}
Tarun
  • 3,162
  • 3
  • 29
  • 45
0

ES6-way without unused iterating:

const getRarest = originalArray => {
    const temp = {};
    const counts = originalArray
      .map(item => {
         temp[item] = 0;
         return item;
      })
     .reduce((acc, item) => {
         acc[item]++;
         return acc;
     }, temp);

    const resultArray = Object.entries(counts).sort(
        ([key, val], [bKey, bVal]) => bVal < val
    );

    return (rarest = parseInt(resultArray[0][0]));
};

//Implementation
const arr = [3, 2, 4, 4];
console.log(getRarest(arr));
sandrooco
  • 8,016
  • 9
  • 48
  • 86
0

You can create a dictionary for counting the occurrences of array elements, and then return the key for the lowest count.

function rarestFromArray(arr) {
  // Create dictionary with array element as key and occurence count as value
  var arrMap = arr.reduce(function(obj, val) {
    obj[val] = ++obj[val] || 1;
    return obj;
  }, {});
  // Cache first element as the point of reference
  var rarest = Object.keys(arrMap)[0];

  // Compare and return the lowest count
  for (key in arrMap) {
    // gets first occurence of lowest count
    rarest = arrMap[rarest] > arrMap[key] ? key : rarest;

    // gets last occurence of lowest count
    // rarest = arrMap[rarest] < arrMap[key] ? rarest : key;
  }
  return rarest;
}

var inputArr = [1, 1, 1, 1, 2, 2, 2, 3, 33, 4, 4];
console.log(rarestFromArray(inputArr));
0

const arr = [1, 1, 1, 1, 2, 2, 2, 3, 4, 4, 4, 4]

function leastFrequent(items) {
  let leastFrequentNumber = items[0]
  const counted = items.reduce((acc, item) => { 
    if (!acc[item]) {
      acc[item] = 1
    } else {
      acc[item]++
    }

    if(acc[item] < acc[leastFrequentNumber]) {
      leastFrequentNumber = item
    }

    return acc;
  }, {});

  return leastFrequentNumber
}

console.log(leastFrequent(arr)) //3