Start learning free

LESSON 563 OF 568 · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

Playlist in C++: Two Classes Working Together

Practice O(n) Read the full explanation

A music app keeps playlists: songs in the order they were added. Build it from two classes that work together. A Song holds one song's data. A Playlist keeps a list of Song objects and answers questions about them.

Implement:

  • Song(title, seconds) holds a song's title and its length in seconds;
  • Playlist() starts with no songs. Its methods:
    • add(song) adds a Song at the end of the playlist;
    • remove(title) removes the first song with that title and returns true; if no song has that title, it changes nothing and returns false;
    • totalSeconds() returns the sum of the songs' lengths in seconds (0 for an empty playlist);
    • duration() returns the same total as a string "m:ss": the minutes, a colon, then the seconds with two digits. 5 seconds are "0:05", 750 seconds are "12:30", and 3600 seconds are "60:00": the minutes are never padded.

The starter code spells every name the way your language does.

The input is a list of operations, applied in order to one new playlist. The output lists what the remove, totalSeconds and duration calls return, in order, with booleans printed as True and False.

 

Example 1:

Input:
    add(Song("Intro", 65))
    add(Song("Sunrise", 200))
    totalSeconds()
    duration()
    remove("Intro")
    duration()
Output: 265 4:25 True 3:20
Explanation: The two songs last 65 + 200 = 265 seconds: 4 minutes (240 seconds) and 25 seconds.
After "Intro" is removed, only the 200 seconds of "Sunrise" are left: 3 minutes and 20 seconds.

Example 2:

Input:
    duration()
    remove("Rain")
    totalSeconds()
Output: 0:00 False 0
Explanation: The playlist is empty: it lasts 0 seconds, and there is no "Rain" to remove.

Example 3:

Input:
    add(Song("Echo", 30))
    add(Song("Echo", 45))
    add(Song("Rain", 5))
    remove("Echo")
    totalSeconds()
    remove("Echo")
    remove("Echo")
    duration()
Output: True 50 True False 0:05
Explanation: Two songs are called "Echo". The first remove takes only the first one, the 30 seconds,
so 45 + 5 = 50 seconds are left. The second remove takes the other "Echo", and the third finds none.
Only "Rain" is left: 5 seconds, written 0:05.

 

Constraints:

  • 1 <= seconds <= 3600
  • A title is one word of letters and digits. Titles are compared exactly: "Rain" and "rain" are different titles.
  • At most 200 operations.
STEP 1 OF 16
    Ctrl + Enter to check

    C++ · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

    Playlist in C++, explained

    Problem overview

    A music app keeps playlists: songs in the order they were added. You build it from two classes. A Song holds one song's data, its title and its length in seconds. A Playlist keeps a vector of Song objects and answers questions about them:

    • add(song) puts a song at the end;
    • remove(title) removes the first song with that title and returns true, or changes nothing and returns false when there is none;
    • totalSeconds() returns the sum of the lengths, 0 for an empty playlist;
    • duration() returns the same total as a string "m:ss": minutes, a colon, and the seconds with two digits.

    In the first example the playlist gets Intro (65 seconds) and Sunrise (200). The total is 265 seconds, which is 4 minutes (240 seconds) and 25 seconds, so duration() is 4:25. After remove("Intro") returns true, only 200 seconds are left, and the duration is 3:20.

    Approach: one class holds the data, the other holds the list

    Splitting the work this way keeps each class simple. Song has nothing to do but remember two values. Playlist keeps its songs in a private vector, so only its own methods can change the list, and the numbers it reports always match what is inside.

    The methods then follow from simple ideas:

    • remove walks the vector by index. At the first match, it erases that element and returns true straight away, which is why only the first song with the title goes. If the loop ends without a match, the answer is false.
    • totalSeconds adds up every song's seconds.
    • duration reuses totalSeconds and formats the result. The minutes are the total divided by 60, using whole-number division. The seconds are the remainder, total % 60.

    Step by step

    1. In Song, declare string title; and int seconds; under public:, and store the constructor's parameters with this->. They are public because Playlist reads them.
    2. In Playlist, declare vector<Song> songs; under private:.
    3. In add, call songs.push_back(song).
    4. In remove, write a for loop with an index i from 0 up to songs.size(). If songs[i].title == title, erase the element with songs.erase(songs.begin() + i) and return true. After the loop, return false.
    5. In totalSeconds, keep a total starting at 0, add song.seconds for each song and return it.
    6. In duration, store totalSeconds(), then compute minutes and seconds. If seconds is below 10, return the minutes, ":0" and the seconds. Otherwise return the minutes, ":" and the seconds.

    The solution in C++

    class Song {
    public:
        string title;
        int seconds;
    
        Song(string title, int seconds) {
            this->title = title;
            this->seconds = seconds;
        }
    };
    
    class Playlist {
    private:
        vector<Song> songs;
    public:
        void add(Song song) {
            songs.push_back(song);
        }
    
        bool remove(string title) {
            for (int i = 0; i < songs.size(); i++) {
                if (songs[i].title == title) {
                    songs.erase(songs.begin() + i);
                    return true;
                }
            }
            return false;
        }
    
        int totalSeconds() {
            int total = 0;
            for (Song& song : songs) {
                total += song.seconds;
            }
            return total;
        }
    
        string duration() {
            int total = totalSeconds();
            int minutes = total / 60;
            int seconds = total % 60;
            if (seconds < 10) {
                return to_string(minutes) + ":0" + to_string(seconds);
            }
            return to_string(minutes) + ":" + to_string(seconds);
        }
    };
    

    A run

    Take a playlist with Echo (30), Echo (45) and Rain (5), then call remove("Echo"), totalSeconds(), remove("Echo"), remove("Echo") and duration(). The results are:

    True 50 True False 0:05
    

    The first remove takes only the first Echo, so 45 + 5 = 50 seconds are left. The second takes the other one, and the third finds none. Only Rain remains: 5 seconds, written 0:05.

    For an empty playlist, duration() is 0:00, remove("Rain") is false and totalSeconds() is 0. Single songs of 5, 750 and 3600 seconds give 0:05, 12:30 and 60:00; 59, 60 and 61 seconds give 0:59, 1:00 and 1:01.

    Details that matter

    • erase takes a position, not an index. songs.begin() + i is the position of element i. After the erase, the elements after it move up one place.
    • Return right after the erase. The loop changes the vector it is walking through. Stopping at once is both what the task asks (only the first match goes) and the safe thing to do.
    • to_string turns an int into a string, so the pieces can be joined with +.
    • Minutes are never padded. Only the seconds get a leading zero, so 3600 seconds is 60:00, not 01:00:00.
    • Signed index and size(). songs.size() is unsigned, and the loop compares it with an int. That is fine for these small sizes. Be careful with expressions like songs.size() - 1: on an empty vector the unsigned subtraction wraps around, and the result is 18446744073709551615.

    Complexity

    For n songs, add is O(1) on average. remove is O(n): the loop may look at every song, and the erase moves the elements after the removed one. totalSeconds is O(n), and so is duration, since it calls totalSeconds. The extra space is O(1) apart from the stored songs.

    Edge cases and common mistakes

    • Not padding the seconds. Dropping the ":0" branch gives 0:5 for 5 seconds, 60:0 for 3600 and 1:0 for 60. Every single-digit seconds value needs the zero, including 0 itself.
    • Removing every match. Only the first song with the title goes. Two songs can share a title.
    • Matching titles loosely. Rain and rain are different titles, and == on strings compares them exactly.
    • Forgetting return false. A non-void function that reaches its closing brace without returning a value is undefined behaviour in C++. The return false; after the loop covers the case of no match.
    • Empty playlist. The total is 0, the duration is 0:00, and remove returns false.

    Testing

    OperationsResults
    add Intro 65, add Sunrise 200, totalSeconds, duration, remove Intro, duration265 4:25 True 3:20
    duration, remove Rain, totalSeconds (empty playlist)0:00 False 0
    add Echo 30, add Echo 45, add Rain 5, remove Echo, totalSeconds, remove Echo, remove Echo, durationTrue 50 True False 0:05
    Keep going with C++500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free