I have an array of objects as per below.
songs = [
{
track_name: "name of track" ,
track_genres: ["chamber pop","indie pop"] },
{
track_name: "name of track 2" ,
track_genres: ["dutch r&b","indie soul", "indie pop"] },
{
track_name: "name of track 3" ,
track_genres: ["indie pop","chamber pop","indie soul"] }
]
I have another mapping object that looks like this
genres = [
{
name: "Pop",
children: [{name:"chamber pop"},{name:"indie pop"}]
},
{
name: "R&B",
children: [{name:"dutch r&b"}]
},
{
name: "Soul",
children: [{name:"indie soul"}]
}
]
What I want to do is for each track, go through the track genres, and use the "genres" variable to assign the parent genres for each track. Parent genre ideally shouldn't be repeated.
Expected Output:
const songs = [
{
track_name: "name of track",
track_genres: ["chamber pop", "indie pop"],
parent_genres: ["Pop"] },
{
track_name: "name of track 2",
track_genres: ["dutch r&b", "indie soul", "indie pop"],
parent_genres: ["R&B","Soul","Pop"] },
{
track_name: "name of track 3",
track_genres: ["indie pop", "chamber pop", "indie soul"],
parent_genres: ["Pop", "Soul"] }
];
Quoting the OP ...
What I want to do is for each track, go through the track genres, and use the "genres" variable to assign the parent genres for each track.
Taking the two data-structures into account, the goal most easily can be achieved by looking up the main-genre by a sub-genre. This is where maps do shine, due to their efficiency in lookup-speed.
Thus one firstly needs to create such a Map
based lookup-table by a flattening flatMap
based transformation of the nested genres
-specific data, where each genre-item's children
-array is going to be map
ped as e.g. subGenres
in order to create lookup-entries for each found/existing sub-genre specific name
.
const genres = [{
name: "Pop",
children: [{ name: "chamber pop" }, { name: "indie pop" }],
}, {
name: "R&B",
children: [{ name: "dutch r&b" }],
}, {
name: "Soul",
children: [{ name: "indie soul" }],
}];
const genreBySubGenreLookup = new Map(
genres
.flatMap(({ name: genreName, children: subGenres }) =>
subGenres
.map(({ name }) => [ name, genreName ])
)
);
console.log(
'genreBySubGenreLookup.get("chamber pop") ...',
genreBySubGenreLookup.get("chamber pop"),
);
console.log(
'genreBySubGenreLookup.get("indie pop") ...',
genreBySubGenreLookup.get("indie pop"),
);
console.log(
'genreBySubGenreLookup.get("dutch r&b") ...',
genreBySubGenreLookup.get("dutch r&b"),
);
console.log(
'genreBySubGenreLookup.get("indie soul") ...',
genreBySubGenreLookup.get("indie soul"),
);
console.log({ lookup: Object.fromEntries(genreBySubGenreLookup) });
.as-console-wrapper { min-height: 100%!important; top: 0; }
Now one can focus on the OP's main task which is enhancing each item of the provided songs
track-list.
Since the lookup-table is already in place, one might think that the remaining map
-based (of cause) task can be implemented pretty straightforward, but the OP has a say again ...
Parent genre ideally shouldn't be repeated.
Even though the array of main-genre names can be created easily and fast due to the lookup, it most probably will feature multiple same values within the array. But creating a Set
instance from an array assures unique set items (array items, once spread again) and spreading such a set creates/casts a new array.
const tracklist = songs
.map(trackItem => {
/*
- the array of main-genre names, can be created easily
and fast due to the lookup, but it most probably will
feature multiple same values within the array.
- creating a `Set` instance from an array assures unique
set items (array items, once spread again).
- spreading a `Set` instance creates/casts a new array.
*/
const parent_genres = [...new Set(
trackItem
.track_genres
.map(subGenre => genreBySubGenreLookup.get(subGenre))
)];
// returns a new track-item which gets created by ...
return {
// - spreading the current track-item into an (empty) object,
...trackItem,
// - assigning the just created array of unique genre names.
parent_genres,
};
});
console.log({ tracklist, songs });
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
const songs = [{
track_name: "name of track",
track_genres: ["chamber pop", "indie pop"],
}, {
track_name: "name of track 2",
track_genres: ["dutch r&b", "indie soul", "indie pop"],
}, {
track_name: "name of track 3",
track_genres: ["indie pop", "chamber pop", "indie soul"],
}];
const genres = [{
name: "Pop",
children: [{ name: "chamber pop" }, { name: "indie pop" }],
}, {
name: "R&B",
children: [{ name: "dutch r&b" }],
}, {
name: "Soul",
children: [{ name: "indie soul" }],
}];
const genreBySubGenreLookup = new Map(
genres
.flatMap(({ name: genreName, children: subGenres }) =>
subGenres
.map(({ name }) => [ name, genreName ])
)
);
</script>