How to get the only different value inside an array in Javascript?

Asked

Viewed 116 times

3

I saw many questions showing how to get unique values in an array, but none solved my problem. I get an array like this:

[ 1, 1, 1, 2, 1, 1 ]

I want to determine the unique value within it, which, in this case, is: 2.

I have a code that solves the problem with small values, but, with very large values, it fails.

Follows the code:

function findUniq(arr) {
  var result;
  arr.forEach((value, index, self) => {
    var lengthAll = []; 
    self.map(x => {
      if(x === value) {
        lengthAll.push(x);
      }
    })
    if (lengthAll.length === 1) {
      result = lengthAll[0];
    }
  });
  return result;
}

How to improve performance with big values?

  • 2

    What if you have two unique values? For example, in: [1, 1, 2, 3]?

  • In my problem, there’s always one different value.

  • "but, with very large values, it fails" - which is the fault?

  • I don’t know exactly. It’s a Codewars Kata. In random tests, which are with large values sometimes, it exceeds the limit of 12 seconds of processing and breaking

  • 1

    @Vinibrasil, the fault is the excessively long time, which occurs quadratic algorithms that perform on a large number of elements. If it has 1e5 elements, 1e10 iterations will be made, which is absurd and would take a lot longer than needed for this type of problem.

  • 1

    The evening I publish an answer, but for now the load tests are here: https:/jsbench.me/awkpdlrj0d

Show 1 more comment

2 answers

5


I think you’re complicating a lot by using the Array.prototype.map there. You don’t actually need to map the array to solve this problem. It looks like you’re using the Array.prototype.map as a substitute for Array.prototype.forEach, what is an inaccurate use.

In addition, the solution proposed in the question has quadratic time complexity, which means that for each element of the array, a full scan will be done. For example, for an array of 100 elements, 1002 iterations will be performed.

To learn more about this type of measure, see Definition of the "Big O" notation.


As far as I understand, there is no way to solve this problem with less than O(n).

This means that for any array, you must necessarily scroll through each element to check for any guaranteed unique member.

Solving with a map and only a scan for each element of the original array, one has something like:

function findUniqueElement(arr) {
  const map = new Map();

  for (const el of arr) {
    // Para cada elemento do array original, criamos um
    // registro no mapa `map` para determinar sua frequência:
    map.set(el, (map.get(el) || 0) + 1);
  }

  // Para cada elemento (sem repetição) do mapa, verificaremos
  // e retornaremos o primeiro único encontrado:
  for (const [entry, count] of map.entries()) {
    if (count === 1) return entry;
  }

  return undefined;
}

console.log(findUniqueElement([1, 1, 2, 2, 3, 3, 4])); //=> 4
console.log(findUniqueElement([1, 1, 2, 2, 3, 4])); //=> 3 (somente o primeiro único é retornado)
console.log(findUniqueElement([1, 1, 2, 2, 3, 3])); //=> undefined

The above algorithm complexity approaches O(2n) (considered linear), which is much better than O(n2) (quadratic).

Remember that this solution returns only the first single element found. If the occurrence of one more unique value is possible, an alternative is to return an array:

function findUniqueElements(arr) {
  const map = new Map();

  for (const el of arr) {
    map.set(el, (map.get(el) || 0) + 1);
  }

  const uniqueElements = [];
  for (const [entry, count] of map.entries()) {
    if (count === 1) uniqueElements.push(entry);
  }
  return uniqueElements;
}

console.log(findUniqueElements([1, 1, 2, 2, 3, 4])); //=> [3, 4]
console.log(findUniqueElements([1, 1, 2, 2, 3, 3])); //=> []

0

This function returns the first unique value in the array, and returns null if none is unique.

function findUniq(arr) {
  let uniq = {};

  //Para cada elemento do array é criado um index no objeto 'uniq' e incrementado a quantidade de vezes que esse elemento aparece.
  arr.forEach(a => uniq[a] = uniq[a] ? uniq[a] + 1 : 1);
  
  //Com o objeto de contagem pronto, é possivel iterá-lo até encontrar o primeiro elemento que possui apenas uma recorrência
  for (i in uniq)
    if (uniq[i] === 1)
      return i

  //caso nenhum elemento possua apenas uma recorrência, um valor nulo é retornado
  return null;
}

console.log(findUniq([1, 1, 1, 2, 1, 1]))

  • 3

    It would be nice to add an explanation of how the algorithm works. It would add value to answer.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.