0

let arrr = [7, 9, 30, 40, 50, 8, 1, 2, 3, 40, 90,2, 88,1];

output=[0, 1, 2, 3, 4, 5, 6, 7, 8 ,10, 12 ]

I saved this code at javascript playground here.

Question: I am trying to get all the index of unique elements in array. I have tried the code below to get the unqiue array but i do not know how to extract its index to give the expected output as above.

let ar = [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 2, 1];
let unique = ar.filter((value, index) => {
  return ar.indexOf(value) == index;
});
console.log(unique);
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • 3
    How is that output achieved? – 0stone0 Apr 19 '22 at 09:28
  • 1
    I guess that the problem is not correctly stated. You are looking for the indexes of the *first instance* of every value. –  Apr 19 '22 at 09:30
  • Get the index of every element and `.add()` it into a `Set` – Andreas Apr 19 '22 at 09:33
  • @Andreas the index to each element will be unique, so the `Set` can't be used that way. Stuart provides the correct use of `Set` below in an answer below. – Mulan Apr 23 '22 at 12:58
  • @Mulan Typo... :/ should have been _"Get the `.indexOf()` of..."_ like in my answer – Andreas Apr 23 '22 at 13:23

4 Answers4

2

.indexOf() will always return the index of the first match. If we combine that with a Set we get the expected output:

let input = [7, 9, 30, 40, 50, 8, 1, 2, 3, 40, 90, 2, 88, 1];
const indices = input.map(el => input.indexOf(el));
const output = new Set(indices);
const output_as_array = [...output];  // if you need an actual array

console.log(output_as_array);
Andreas
  • 21,535
  • 7
  • 47
  • 56
  • using `indexOf` in a loop has [quadratic complexity](https://en.wikipedia.org/wiki/Big_O_notation#Orders_of_common_functions). See Scott and Stuarts answer for the correct uses of O(1) operations in the loop. – Mulan Apr 23 '22 at 13:43
  • @Mulan Sorry, but who cares (other than you as we can see below almost every answer...) about the "performance" with an array that size... There's no indication that this part is in anyway "performance" relevant. Even if OP is using an array with thousands of entries, `.indexOf()` (most likely) won't be the slowest part in the script - which only a profiler can tell. But each as he thinks. – Andreas Apr 23 '22 at 14:31
  • sorry, but performance and correctness is relevant to all computer programs. sorry, but if you cannot reason correctly about solving small problems you will never solve larger ones. sorry, but you should be more open to constructive input. – Mulan Apr 23 '22 at 14:39
2

Use a set to record numbers that have already been seen, and add the index to an array if it has not been see.

function uniqueIndices(arr) {
    const seen = new Set();
    const indices = [];
    for (const [i, n] of arr.entries()) {
        if (!seen.has(n)) {
            seen.add(n);
            indices.push(i);
        }
    }
    return indices;
}

This also works well as a generator:

function *uniqueIndices(arr) { 
    const seen = new Set(); 
    for (const [i, n] of arr.entries()) { 
        if (!seen.has(n)) { 
            seen.add(n);
            yield i;
        }
    } 
}
console.log([...uniqueIndices([7, 9, 30, 40, 50, 8, 1, 2, 3, 40, 90,2, 88,1])])
Stuart
  • 9,597
  • 1
  • 21
  • 30
  • this answer and @Scott's are the only ones (currently) that process the array in O(n) time. answers using `.indexOf` have abysmal performance. nice job :D – Mulan Apr 23 '22 at 12:54
1

A simple function which iterates the list just once, storing the value and index in a Map, simply testing whether it's already there before adding a new one:

const uniqueIndices = (xs) =>
  [...xs .reduce ((found, x, i) => found .has (x) ? found : found .set (x, i), new Map()) .values ()]

const arr = [7, 9, 30, 40, 50, 8, 1, 2, 3, 40, 90, 2, 88, 1]

console .log (uniqueIndices (arr))
.as-console-wrapper {max-height: 100% !important; top: 0}
Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
0
  1. Get all the unique values
  2. Map over the uniques to use indexOf on the original array to get the indexes of the uniques

let arrr = [7, 9, 30, 40, 50, 8, 1, 2, 3, 40, 90,2, 88,1];
let unique = arrr.filter((v, i, a) => a.indexOf(v) === i);

let uniquesIndexes = unique.map(u => arrr.indexOf(u));
console.log(uniquesIndexes)

Output:

[
  0,
  1,
  2,
  3,
  4,
  5,
  6,
  7,
  8,
  10,
  12
]
0stone0
  • 34,288
  • 4
  • 39
  • 64