What do I mean with this? First let's look at some code I wrote:
let names = ['James', 'james', 'bob', 'JaMeS', 'Bob'];
let uNames = {};
names.forEach(n => {
let lower = n.toLowerCase();
if (!uNames[lower]) {
uNames[lower] = n;
}
});
names = Object.values(uNames);
console.log(names); // >>> (2) ["James", "bob"]
The goal here is to unique the given array case insensitive but keep one of the original inputs.
I was wondering if there is a more elegant/better performing solution to this problem than the one I came up with.
Just converting the whole array to lowercase before making it unique is not a solution, because I'd like the end result to consist only of values which were already in the input array. Which one (e.g. James or james or JaMeS) is not relevant.
I was wondering if there is a more elegant/better performing solution to this problem than the one I came up with.
Use a Map:
let names = ['James', 'james', 'bob', 'JaMeS', 'Bob'];
let uNames = new Map(names.map(s => [s.toLowerCase(), s]));
console.log([...uNames.values()]);
The constructor of Map can take an array of pairs (nested arrays with 2 values: key and value). The Map will maintain a unique list of keys so while it is constructed previously stored values will get overwritten if the key is the same.
Once you have the Map, you can iterate over the values with .values().
You could also use the Object.fromEntries method, which at the time of writing, is a stage 4 proposal (Draft ES2020) implemented in Chrome, Firefox, Opera and Safari:
let names = ['James', 'james', 'bob', 'JaMeS', 'Bob'];
let uNames = Object.fromEntries(names.map(s => [s.toLowerCase(), s]));
console.log(Object.values(uNames));
As you can see, the approach is quite similar.
The above will collect the last occurrence, in order of first occurrence.
In case you want to collect the first occurrence, you can just reverse the input first, and then continue as above. Then the output will have collected the first occurrence, in order of last occurrence.
In case you really need the first occurrences in order of first occurrence, you can use reduce as follows:
let names = ['James', 'james', 'bob', 'JaMeS', 'Bob'];
let uNames = names.map(s => s.toLowerCase()).reduce((map, s, i) =>
map.get(s) ? map : map.set(s, names[i])
, new Map);
console.log([...uNames.values()]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With