Skip to content Skip to sidebar Skip to footer

Remove All Elements That Occur More Than Once From Array

Before people think this is the same as all these other answers on Stack Overflow regarding removing duplicates can you please look at what is returned as opposed to what I am look

Solution 1:

In short: keep the value if the position of the first occurrence of the element (indexOf) is also the last position of the element in the array (lastIndexOf).

If the indexes are not equal then the value is duplicated and you can discard it.

const a = ['Ronaldo', 'Pele', 'Maradona', 'Messi', 
           'Pele', 'Messi', 'Jair', 'Baggio', 'Messi', 
           'Seedorf'];

const uniqueArray = a.filter(function(item) {
  return a.lastIndexOf(item) == a.indexOf(item);
});

console.log(uniqueArray);
/* output:  ["Ronaldo", "Maradona", "Jair", "Baggio", "Seedorf"] */

Codepen Demo

Solution 2:

You can count the item in each iteration so that you can include that in the condition:

const a = ['Ronaldo', 'Pele', 'Maradona', 'Messi', 'Pele'];

const uniqueArray = a.filter(function(item, pos) {
  var c = a.filter(i => i==item).length;
  return a.indexOf(item) == pos && c <= 1;
})

console.log(uniqueArray);

Though the better solution would be to compare the index of the current array item with Array.prototype.indexOf() and Array.prototype.lastIndexOf():

const a = ['Ronaldo', 'Pele', 'Maradona', 'Messi', 'Pele'];

const uniqueArray = a.filter(function(item, pos) {
  return a.indexOf(item) === a.lastIndexOf(item);
})

console.log(uniqueArray);

Solution 3:

You can utilise a Map to count how many times each entry shows up and then only take the ones that only do so once.

const a = ['Ronaldo', 'Pele', 'Maradona', 'Messi', 'Pele'];

const uniqueArray = onlyUniqueItems(a);

console.log(uniqueArray)


functiononlyUniqueItems(array) {
  const map = newMap();
  const result = [];
  
  array.forEach(item => {
    let amount = map.get(item) || 0;
    map.set(item, ++amount); //pre-increment and then set the amount
  });
  
  map.forEach((amount, item) => {
    if (amount == 1) {
      result.push(item);
    }
  });
  
  return result;
}

This will run in O(2n) as you will have to do two scans at most. You can achieve a similar result using a plain object and set key-values on it but a Map has the advantage of preserving the type of the items you had, whereas a plain object will convert all keys to strings:

const a = [1, 2, 3, 3, "4", "4", "5"];

const uniqueArray = onlyUniqueItems(a);
const uniqueArrayUsingObject = onlyUniqueItemsUsingObject(a);

console.log(uniqueArray)
console.log(uniqueArrayUsingObject)


functiononlyUniqueItems(array) {
  const map = newMap();
  const result = [];
  
  //count occurences
  array.forEach(item => {
    let amount = map.get(item) || 0;
    map.set(item, ++amount); //pre-increment and then set the amount
  });
  
  //extract only the items that show once
  map.forEach((amount, item) => {
    if (amount == 1) {
      result.push(item);
    }
  });
  
  return result;
}


functiononlyUniqueItemsUsingObject(array) {
  const map = {};
  const result = [];
  
  //count occurences
  array.forEach(item => {
    let amount = map[item] || 0;
    map[item] = ++amount; //pre-increment and then set the amount
  });
  
  //extract only the items that show onceObject.entries(map).forEach(([item, amount]) => {
    if (amount == 1) {
      result.push(item);
    }
  });
  
  return result;
}

Solution 4:

The naive way would be to check for more than one occurence:

   a.filter((el, i) => !(a.indexOf(el) !== i || a.indexOf(el, i) > -1)));

Or a more complicated one with multiple Sets (but O(n)):

const found = newSet, values = newSet;

  for(const el of a)
   if(!found.has(el)) {
     found.add(el);
     values.add(el);
   } elseif(values.has(el) {
     values.delete(el);
   }
 }

 const result = [...values.values()];

Solution 5:

Why not to use Set?

const theSet = newSet(a);
const values = set.values();
const uniqueArray = Array.from(values);

Post a Comment for "Remove All Elements That Occur More Than Once From Array"