2

I'm trying to transform this sort into a unique sort:
const sort = arr => arr.sort((a, b) => a - b);

I tried this:

const uniqSort = arr => {
    const breadcrumbs = {};
    for(let i =0; i<arr.length; i++){ 
        if(breadcrumbs[arr[i]]){ 
            arr.splice(i,1)
        } else { 
            breadcrumbs[arr[i]] = true;
        }
    }
    return arr.sort((a, b) => a - b);
};

for some reason it doesn't work properly, can anyone know why?

when I input uniqSort([4,2,2,3,2,2,2]);
the output is [2,2,3,4] instead of [2,3,4]

Mister Jojo
  • 20,093
  • 6
  • 21
  • 40
  • 2
    What is a unique sort? – ibrahim mahrir Oct 27 '20 at 01:39
  • 1
    Hello please add an example about what the unique sort would do – Zack Heisenberg Oct 27 '20 at 01:40
  • 2
    Add the thing you are trying to sort, and the desired result. – August Kimo Oct 27 '20 at 01:42
  • removing any duplicates from the array and then sorting it examples: ``` uniqSort([4,2,2,3,2,2,2]); // => [2,3,4] uniqSort([1,5,2,1]); // [1,2,5] ``` – Ahmed Anwar Oct 27 '20 at 01:44
  • Never `splice` and array while looping it from left to right. Reverse the order of the `for` loop: `for(let i = arr.length - 1; 0 <= i; i--)` or substract 1 from `i` each time you `splice` an element: `arr.splice(i, 1); i--;` – ibrahim mahrir Oct 27 '20 at 01:44
  • why is it wrong to splice an array while looping from left to right ? – Ahmed Anwar Oct 27 '20 at 01:51
  • @AhmedAnwar see the duplicate link. Basically when you remove and item from the array, you are skipping the element right after it because `i` is incremented while the array structure changes because of the removed item. – ibrahim mahrir Oct 27 '20 at 01:54
  • ... for example, if `arr` is `[a, b, c, d, e]`, and if `i` is `2` (`arr[i]` is `c`), if you call `splice(i, 1)`, the array `arr` becomes `[a, b, d, e]` and `i` becomes `3` (for the next iteration). Now `arr[i]` is `arr[3]` which is `e`, that means that you **skipped** the element `d`. Looping the array backwards doesn't have this issue because the change in the array structure affects elements that are already treated, unlike looping it from left to right which affect the order of elements that are yet to be treated. Decrementing the index `i` also solves the problem. – ibrahim mahrir Oct 27 '20 at 01:56
  • @AhmedAnwar try this let arr = [1,0,5,9,6,9] let sortedUniq = arr.filter( function(val, idx, self) { return self.indexOf(val) === idx }).sort((a, b) => a - b) console.log(sortedUniq) – user3738936 Oct 27 '20 at 02:01
  • The next element will take the place of the removed element, and since the index of the removed element (now occupied by the element after it) is already handled, that element will be skipped – ibrahim mahrir Oct 27 '20 at 02:04
  • Thanks a lot Ibrahim, you really helped... it works well now – Ahmed Anwar Oct 27 '20 at 02:47

1 Answers1

3

You are modifying the same array as you iterating.

const uniqSort = arr => {
  const breadcrumbs = {};
  const newArray = [];
  for (let i = 0; i < arr.length; i++) {
    if (!breadcrumbs[arr[i]]) {
       breadcrumbs[arr[i]] = true;
       newArray.push(arr[i]);
    }
  }
  return newArray.sort((a, b) => a - b);
};

If you are looking for quick solution, how to filter duplicities from array, you can convert it to Set and then back to array.

const uniqSort = arr => {
  return Array.from(new Set(arr)).sort((a, b) => a - b);
};

Jan Cizmar
  • 372
  • 2
  • 11
  • Perfect answer! You can make the shorter answer even more shorter by removing the block `{}` and the `return` statement and use the implicit return of arrow functions: `const uniqSort = arr => Array.from(...).sort(...);` – ibrahim mahrir Oct 27 '20 at 01:49
  • what's wrong with modifying the same array ? i know the Set solution, recently I started to deep dive into algorithms so i'm trying different things – Ahmed Anwar Oct 27 '20 at 01:50
  • You can find more here. https://stackoverflow.com/questions/9882284/looping-through-array-and-removing-items-without-breaking-for-loop – Jan Cizmar Oct 27 '20 at 21:13