Adding up times with Reduce
demo
Today we will be using Array.prototype.map
and Array.prototype.reduce
to figure out the total runtime of given videos in hours, minutes and seconds.
So we are given a list of items each mimicking a video and each one has a data-time
attribute telling us the length of the video in the format minutes:seconds
, and we need to figure out how to pull them out of the DOM, convert them to numbers, make them into minutes and seconds, add it all up, figure out how many hours, minutes and seconds there are totally, then finally console.log
those actual values.
Here is sample of list items given:
<ul class="videos">
<li data-time="5:43">Video 1</li>
<li data-time="2:33">Video 2</li>
<li data-time="3:45">Video 3</li>
<li data-time="0:47">Video 4</li>
<li data-time="5:21">Video 5</li>
</ul>
First thing we want to do is select all of those nodes
const timeNodes = document.querySelectorAll("[data-time]");
We are not selecting list items because we don't know if it's always going to be a list item so we will select anything with a data-time
attribute on it.
Now this timeNodes
is a NodeList and to use map
we need an Array, so we need to convert this from a node list into an array of actual time strings.
const timeNodes = Array.from(document.querySelectorAll("[data-time]"));
Now timeNodes
is an array of list items.
We will now extract time out of this array of list items.
const seconds = timeNodes.map((node) => node.dataset.time);
Now seconds
is an array of strings (containing all the times)
Now we want to convert the time into just seconds. The format in which we have our time right now is minutes:seconds
so we need to split this string on the :
.
const seconds = timeNodes.map((node) => node.dataset.time).map((timeCode) => {
const [mins, secs] = timeCode.split(":");
But the problem we run into here is after splitting what we get is also a string and we need numbers to do any kind of mathematical calculation.
So we need to map over the array again and use parseFloat
to convert the string into numbers.
We can see how parseFloat
solves our problem:
const seconds = timeNodes
.map((node) => node.dataset.time)
.map((timeCode) => {
const [mins, secs] = timeCode.split(":").map(parseFloat);
return mins * 60 + secs
});
This gives us all the time in seconds.
Now that we have all the times in seconds, we need to add them all up and we are going to use reduce
for that.
const seconds = timeNodes
.map((node) => node.dataset.time)
.map((timeCode) => {
const [mins, secs] = timeCode.split(":").map(parseFloat);
return mins * 60 + secs;
})
.reduce((total, vidSeconds) => total + vidSeconds);
This gives us the total number of seconds of every single video added together.
Time to chop down the total seconds into hours, minutes and seconds.
let secondsLeft = seconds;
const hours = Math.floor(secondsLeft / 3600);
We use
Math.floor
to get rid of the decimal part, for example 2.5 hours needs to be converted to 2 hours and we'll convert the remaining 0.5 hours into minutes and seconds1hour=3600seconds
secondsLeft = secondsLeft % 3600;
const mins = Math.floor(secondsLeft / 60);
//1min=60seconds
secondsLeft = secondsLeft % 60;
console.log(`${hours}hours ${mins}minutes ${secondsLeft}seconds`);
This is final output:
and with this our project for the day was completed.
GitHub repo:
Blog on Day-17 of javascript30
Blog on Day-16 of javascript30
Blog on Day-15 of javascript30
Follow me on Twitter
Follow me on Linkedin
DEV Profile
You can also do the challenge at javascript30
Thanks @wesbos , WesBos to share this with us! 😊💖
Please comment and let me know your views
Top comments (8)
I will love to have some collaborative projects with you. You can join my discord server for collaborative projects here.
Sure I would love to
You can share any of the ideas you have for a group project or can ping me on the server
Definitely.
12 days more to go...
Aye
Nice 😊
Thanks