values - javascript push unique object to array




How to get distinct values from an array of arrays in JavaScript using the filter() method? (5)

Effective solution:

O(n) operations, where n is the length of x array

O(n) memory space, where n is the length of x array

const x = [[1, 2], [3, 4], [1, 2]];

const arrayTable = Object.create(null);

const uniqueArrays = x.filter(arr => {
  const arrStr = JSON.stringify(arr);

  if (!arrayTable[arrStr]) {
    arrayTable[arrStr] = true;
    return true;
  }

  return false;
});

console.log(uniqueArrays);

This question already has an answer here:

I have an array like this:

let x = [[1, 2], [3, 4], [1, 2], [2, 1]];

What should I do to retrieve an array without the duplicates?

[[1, 2], [3, 4], [2, 1]];

I would like to use the filter method. I tried this but it doesn't work:

x.filter((value,index,self) => (self.indexOf(value) === index))

EDIT: as I specified to use the filter method, I don't think this question is a duplicate. Also, I got several interesting answers.


Filter just causes things to get into O(n^2).

The currently accepted answer uses .filter((itm, idx, arr) => arr.indexOf(itm) === idx) which will cause the array to be iterated each time during each iteration... n^2.

Why even go there? Not only that, you need to parse in the end. It is a lot of excess.

There is no real good way to filter without hitting O(n^2) here.

Instead, just use reduce. It is very straightforward and fast easily accomplishing O(n).

"Bin reduce the set to unique values."

let x = [[1, 2], [3, 4], [1, 2], [2, 1]];
let y = Object.values(x.reduce((p,c) => (p[JSON.stringify(c)] = c,p),{}));
console.log(y);

If you were to have to go the route of filter, then n^2 must be used. You can iterate each item looking for existence using every.

"Keep every element which does not have a previous duplicate."

let x = [
  [1, 2],
  [3, 4],
  [1, 2],
  [2, 1]
];
let y = x.filter((lx, li) =>
  x.every((rx, ri) =>
    rx == lx ||
    (JSON.stringify(lx) != JSON.stringify(rx) || li < ri))
);
console.log(y);


The equivalent to

x.filter((value,index,self) => (self.indexOf(value) === index))

would be

x.filter((v,i,self) => {
for1:
  for (let j = 0; j < self.length; j++) {
    if (i == j) {
      return true;
    }
    if (self[j].length != v.length) {
      continue;
    }
    for (let k = 0; k < v.length; k++) {
      if (self[j][k] != v[k]) {
        continue for1;
      }
    }
    return false;
  }
  return true;
})

Unlike some of the other answers, this does not require a conversion to string and can thus work with more complex values. Use === instead of == if you want.

The time complexity is not great, of course.


This is a solution with time complexity of O(n) where n is the number of elements in your array.

Using the filter method as the OP wants it:

    const x = [[1, 2], [3, 4], [1, 2], [2, 1]];
    const s = new Set();


    const res = x.filter(el => {
      if(!s.has(el.join(""))) {
        s.add(el.join(""));
        return true;
      }
      return false
    })

    console.log(res)

My personal preference here is to use ForEach as it looks more readable.

const x = [[1, 2], [3, 4], [1, 2], [2, 1]];
const s = new Set();
const res = [];

x.forEach(el => {
  if(!s.has(el.join(""))) {
    s.add(el.join(""));
    res.push(el)
  }
})

console.log(res);

We are using a Set and a simple combination of the elements of the array to make sure they are unique. Otherwise this would become O(n^2).


indexOf does not work on identical instances of arrays / objects type elements within an array, as such arrays just hold references.

In filter function instance you get via parameter v (in below code) is not the same instance as stored in array, making indexOf unable to return the index of it.

In below code, by converting objects to strings we can use indexOf to find duplicates.

let x = [[1, 2], [3, 4], [1, 2], [2, 1]];

console.log(x.
  map(function(v){
    return JSON.stringify(v)
  })
  .filter(function(v, i, o) {
    return o.length == i ? true : o.slice(i + 1).indexOf(v) == -1;
  })
  .map(function(v) {
    return JSON.parse(v)
  })
);







arrays