I got a couple of problems with accesesing JSON data and how to passthrue the right values in functions.
The things I would like to do.
TODO 1: I got this part from the internet and I don't get how I can use the for each to activate the function
Input: for(o in albums) | the o should be the used like this: let albumDur = getAlbumDuration(o)
TODO 2: I want to check how many tracks there are in a album, album is the function parameter that is filled in at
for (const track of data.albums[album].tracks)
Input: track is a single string like any of the title's in my JSON file.
TODO 3: Find the duration based on a title when these 2 values are on the same level of a JSON file.
pseudocode: track = tracks.title but return tracks.dur
let data = await JsonData("jukebox.json");
//populate the dropdown #artistSelector with options coming from data
Object.keys(data.Albums).forEach((o,i)=>{
const artistOption = document.createElement('option');
//TODO give album/artist to getAlbumDuration
let albumDur = getAlbumDuration()
artistOption.innerText = o; // ' ' albumDur;
artistOption.value = o;
document.getElementById("artistSelector").appendChild(artistOption);
});
function getAlbumDuration(album) {
let totalSeconds = 0
//TODO use album to do a for each track in the album
for (const track of data.albums[album].tracks) {
let seconds = getTrackSeconds(track)
totalSeconds = seconds
}
return totalSeconds
}
function getTrackSeconds(track) {
//TODO get dur aka duration by compairing the track name.
for (const artist of data.album.track) {
let text = data.Albums.tracks[track];
const time = text.split(":");
let minuten = parseInt(time[0], 10);
let seconden = parseInt(time[1], 10);
let secDe = minuten*60
let totalTime = seconden secDe
return totalTime
}
}
{
"Albums": {
"Krezip":
{
"artist":"Krezip",
"title":"Days like this",
"tracks": [
{
"title":"Lost without you",
"src":"https://www.youtube.com/embed/zazrmePIL9Y",
"dur":"3:35"
},
{
"title":"I would stay",
"src":"https://www.youtube.com/embed/kfrGFGHU6YA",
"dur":"4:04"
}
]
},
"Cure":
{
"artist":"The Cure",
"title":"Wish",
"tracks": [
{
"title":"A Forest",
"src":"https://www.youtube.com/embed/xik-y0xlpZ0",
"dur":"4:43"
},
{
"title":"Lullaby",
"src":"https://www.youtube.com/embed/ijxk-fgcg7c",
"dur":"4:20"
}
]
},
"Boef":
{
"artist":"Boef",
"title":"slaaptekort",
"tracks": [
{
"title":"EXCUSEER",
"src":"https://www.youtube.com/embed/0mqUTqvko88",
"dur":"2:40"
},
{
"title":"HABIBA",
"src":"https://www.youtube.com/embed/AshBgnrSvyc",
"dur":"3:36"
}
]
}
}
}
CodePudding user response:
let data = {
"Albums": {
"Krezip":
{
"artist":"Krezip",
"title":"Days like this",
"tracks": [
{
"title":"Lost without you",
"src":"https://www.youtube.com/embed/zazrmePIL9Y",
"dur":"3:35"
},
{
"title":"I would stay",
"src":"https://www.youtube.com/embed/kfrGFGHU6YA",
"dur":"4:04"
}
]
},
"Cure":
{
"artist":"The Cure",
"title":"Wish",
"tracks": [
{
"title":"A Forest",
"src":"https://www.youtube.com/embed/xik-y0xlpZ0",
"dur":"4:43"
},
{
"title":"Lullaby",
"src":"https://www.youtube.com/embed/ijxk-fgcg7c",
"dur":"4:20"
}
]
},
"Boef":
{
"artist":"Boef",
"title":"slaaptekort",
"tracks": [
{
"title":"EXCUSEER",
"src":"https://www.youtube.com/embed/0mqUTqvko88",
"dur":"2:40"
},
{
"title":"HABIBA",
"src":"https://www.youtube.com/embed/AshBgnrSvyc",
"dur":"3:36"
}
]
}
}
}
let trackLookup ={};
//populate the dropdown #artistSelector with options coming from data
Object.keys(data.Albums).forEach((o,i)=>{
//const artistOption = document.createElement('option');
//TODO give album/artist to getAlbumDuration
let albumDur = getAlbumDuration(o)
//artistOption.innerText = o; // ' ' albumDur;
// artistOption.value = o;
console.log(`Album ${o} Duration ${albumDur}`);
console.log(`No of tracks ${data.Albums[o].tracks.length}`);
// document.getElementById("artistSelector").appendChild(artistOption);
});
function getAlbumDuration(album) {
let totalSeconds = 0
//TODO use album to do a for each track in the album
for (const track of data.Albums[album].tracks) {
let seconds = getTrackSeconds(track)
totalSeconds = seconds;
trackLookup[track.title]=seconds;
}
return totalSeconds
}
function getTrackSeconds(track) {
//TODO get dur aka duration by compairing the track name.
// for (const artist of data.Albums[track]) {
let text = track.dur;
const time = text.split(":");
let minuten = parseInt(time[0], 10);
let seconden = parseInt(time[1], 10);
let secDe = minuten*60
let totalTime = seconden secDe
return totalTime
// }
}
console.log("Track lookup ",trackLookup);
console.log("Duration for Lost without you" , trackLookup["Lost without you"]);
CodePudding user response:
I think maybe you don't have the right abstractions for the job. Looking at the data, what do we know? Well, data.Albums
an object keyed by artist name and each artist name has an object as a value which has an array of tracks keyed by the key "tracks"
each track of which is an object with a "dur"
key that has a time as a value in string format.
So lets think how we first approach it. What we want to do first is grab all the tracks because we don't care about any of the other information. What if we use map
? to do that?
const albums = Object.keys(data.Albums).map(artistName => data.Albums[artistName].tracks)
See, we know we have an artist name as the keys of Albums. And since we know they have a tracks
property, we can look at data.Albums[artistName].tracks
and just pull it out.
But hold on a second... now we get an array of track arrays like this...
[
[
{
title: 'Lost without you',
src: 'https://www.youtube.com/embed/zazrmePIL9Y',
dur: '3:35'
},
{
title: 'I would stay',
src: 'https://www.youtube.com/embed/kfrGFGHU6YA',
dur: '4:04'
}
],
[
{
title: 'A Forest',
src: 'https://www.youtube.com/embed/xik-y0xlpZ0',
dur: '4:43'
},
{
title: 'Lullaby',
src: 'https://www.youtube.com/embed/ijxk-fgcg7c',
dur: '4:20'
}
]...
]
This is no good. Now, we could reduce
it so that we only have an array of albums rather than an array of arrays of albums.
Lets look at how that might look:
const albums = Object.keys(data.Albums)
.map(artistName => data.Albums[artistName].tracks)
.reduce((albums, currentAlbumArray) => [...albums, ...currentAlbumArray], [])
This says, "Hey, for every album array you've given me, I want a new array of all the previous albums combined with our current album array." Now we're talking! Now we have only a list of albums rather than a list of lists of albums!
What do we need to do now? Well, we need to reduce
it further. We need to get the track durations out of each album. and add them all up. Luckily, you've written a function that does basically that. Here's the modified version:
function getTrackSeconds(trackDuration) {
const [minutes, seconds] = trackDuration.split(":");
let minuten = parseInt(minutes, 10);
let seconden = parseInt(seconds, 10);
let secDe = minuten * 60
return seconden = secDe
}
Nice. Let's use our function with a reduction on the albums
list we already created to get our total seconds!
const totalSeconds = albums.reduce((total, currentTrack) => getTrackSeconds(currentTrack.dur) total, 0);
One last thing... We don't need to do the first reduction. JavaScript has has a handy flatMap
function that takes an array of arrays and gives us back an array off all of the subarrays concatonated. That's what we did with reduce
!
We can change the map().reduce()
to be flatMap
and take away that second section of the code.
So this:
const albums = Object.keys(data.Albums)
.map(artistName => data.Albums[artistName].tracks)
.reduce((albums, currentAlbumArray) => [...albums, ...currentAlbumArray], [])
becomes this:
const albums = Object.keys(data.Albums).flatMap(artistName => data.Albums[artistName].tracks)
Lastly, we don't have to break it up. We can just reduce
our flatMap
right out of the gate. Which leave us, finally with this to get the total seconds of all of the albums:
const totalSeconds = Object.keys(data.Albums)
.flatMap(artistName => data.Albums[artistName].tracks)
.reduce((total, currentTrack) => getTrackSeconds(currentTrack.dur) total, 0)
That's it! That's the entire code excluding your helper function. You see with just these concepts, we're able to make it much simpler.