geek glance
geek glance

Reputation: 111

Javascript remove duplicates from multidimentional array based on first element of array

I want to get unique values from a multidimensional array.

The checking should be done based on the first element of each item.

let arr = [['item 1', 'item 2'],['item 1', 'item 5'],['item 3', 'item 4'], ['item 6', 'item 5']]

So here item 1 is present multiple times so it should return

let arr = [['item 1', 'item 2'],['item 3', 'item 4'], ['item 6', 'item 5']]

Tried this snippet but its checking each and every value of element

 var uniques = [];
  var itemsFound = {};
  for (var i = 0, l = arr.length; i < l; i++) {
    var stringified = JSON.stringify(arr[i]);
    if (itemsFound[stringified]) {
      continue;
    }
    uniques.push(arr[i]);
    itemsFound[stringified] = true;
  }
  return uniques;

Upvotes: 0

Views: 75

Answers (3)

bitifet
bitifet

Reputation: 3669

This produces the exact same result you shown (but oly works for two-dimensional arrays such as the example you gave):

const arr = [['item 1', 'item 2'],['item 1', 'item 5'],['item 3', 'item 4'], ['item 6', 'item 5']];
const arr2 = Array
    .from(
        new Map(
            arr.reverse()
        )
    )
    .reverse()
;
console.log(JSON.stringify(arr2));
// -> [["item 1","item 2"],["item 3","item 4"],["item 6","item 5"]]

Alternative implementation using Object.fromEntries if available could be:

const arr = [['item 1', 'item 2'],['item 1', 'item 5'],['item 3', 'item 4'], ['item 6', 'item 5']];
const arr2 = Object
    .entries(
        Object.fromEntries(
            arr.reverse()
        )
    )
    .reverse()
;
console.log(JSON.stringify(arr2));
// -> [["item 1","item 2"],["item 3","item 4"],["item 6","item 5"]]

...even this would be theoretically less performant than the former.

BUT, if I understood you well, you want to skip repeated values at any position in the inner array (not just first one).

In your input example also 'item 5' is repeated, but its first occurrence comes together with 'item 1' which makes this tuple to be ignored.

Let's add new element: ['item 7', 'item 6']: In previous example this tuple would pass:

// ...
// -> [["item 1","item 2"],["item 3","item 4"],["item 6","item 5"],["item 7","item 6"]]

So, if your intention is to take in account all elements, there is no other option than scanning all subelements:

const arr = [['item 1', 'item 2'],['item 1', 'item 5'],['item 3', 'item 4'], ['item 6', 'item 5'], ['item 7','item 6']];
const seen = new Set();
const arr2 = arr
    .filter(function hasRepetition(items) {
        if ( // Repetition found
            1 + items.findIndex(itm=>seen.has(itm))
        ) return false;
        items.map(seen.add, seen);
        return true;
    })
;
console.log(JSON.stringify(arr2));
// -> [["item 1","item 2"],["item 3","item 4"],["item 6","item 5"]]

...This solution also works --with any dimensions--.

Edit:

This solution works for any length of both (2) dimensions, obviously not for any number of dimensions unless properly tweaked.

Upvotes: 1

Shraga
Shraga

Reputation: 87

An easy way to 'keep' every item that doesn't match your condition is like so

arr.filter(item => item[0] !== arr[0][0])

note that it will delete the 1st item aswell, you can save the 1st item beforehand in a few ways.

Upvotes: 0

Hassan Imam
Hassan Imam

Reputation: 22534

You can use Set to keep track of unique values and based on it you can create your array of unique items using array#reduce.

const arr = [['item 1', 'item 2'],['item 1', 'item 5'],['item 3', 'item 4'], ['item 6', 'item 5']],
      set = new Set(),
      result = arr.reduce((r, a) => {
        if(!set.has(a[0])){
          set.add(a[0]);
          r.push(a);
        }
        return r;
      },[]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Related Questions