What you misunderstood is where the duplicates are removed.
You think the duplicate were removed by the join but they are still there at this moment.
Here's the proof :
const array = [
{ class: "second", fare: "a" },
{ class: "second", fare: "b" },
{ class: "first", fare: "a" },
{ class: "first", fare: "a" },
{ class: "second", fare: "a" },
{ class: "first", fare: "c" }
];
unique(array, ['class', 'fare']);
function unique(arr, keyProps) {
const kvArray = arr.map(entry => {
const key = keyProps.map(k => entry[k]).join('|');
return [key, entry];
});
console.log(kvArray)
const map = new Map(kvArray);
return Array.from(map.values());
}
the line which actually remove duplicates is this one
const map = new Map(kvArray);
a Map
is a structure with no duplicate keys, where you give an array to the map constructor it need to look like this : [[ 1, 'one' ],[ 2, 'two' ]]
where the first value of each pair (here the digits) becomes the map keys while the second value is taken as the value in the map (here the string)
As map can't have duplicate keys, when a key is met for the second time the value replace the previous value, effectively removing duplicates keys
the Map is then transformed back into an array with
Array.from(map.values())
A more commented version of the snippets :
const array = [
{ class: "second", fare: "a" },
{ class: "second", fare: "b" },
{ class: "first", fare: "a" },
{ class: "first", fare: "a" },
{ class: "second", fare: "a" },
{ class: "first", fare: "c" }
];
console.log(unique(array, ['class', 'fare']));
function unique(arr, keyProps) {
/*
for each entry of the array transform it into
[
"entry.class|entry.fare",
entry
]
*/
const kvArray = arr.map(entry => { // for each entry
const key = keyProps // for each prop (here "class" and "fare")
.map(k => entry[k]) // get them from the entry effectively creating
// an array looking like this [entry.class, entry.fare]
.join('|'); // join them with "|" creating the string "class|fare"
return [key, entry]; // return the array ["class|fare", entry]
});
/*
here the kvArray looks like
[
[
"second|a",
{ class: "second", fare: "a" }
],
[
"second|b",
{ class: "second", fare: "b" },
],
[
"first|a",
{ class: "first", fare: "a" },
],
...
]
*/
const map = new Map(kvArray); // create a Map using mechanism explained above
/*
the above line is equivalent to
const map = new Map()
kvArray.forEach( el => map.set(el[0], el[1]) )
*/
// map.values return an Iterator with only the values of the map (the keys are lost)
// meaning we only get back the objects we had at the start
// using Array.from(...) to get an array out of this iterator
return Array.from(map.values());
}
the different revelant documentations Array.map
, Array.join
, Map
, Map.values
, Array.from