Shuffle Method in CodeAcademy exercise

I am having some trouble determine how to go about the shuffle method in the Learn JavaScript tutorial for Lesson 9.

I have this to create a random selection of songs. It works,

//Shuffle to create random set of songs in the lists of songs.
shuffle(){
//total songs variable
//an array to store the list of shufflesongs
var Shufflesongs = [this._songs.length];

//a for loop to loop tee loop thru the list of songs & create random song list in shuffle songs
for (let i = 0; i < this._songs.length; i++) 
{let RandomSong =Math.floor(Math.random()*this._songs.length);
  if (Shufflesongs[i]= [])
    {
      Shufflesongs[i]= this._songs[RandomSong];
    };
};

return Shufflesongs;
}

The second step should be, it seems to me, a nested set of for loops to check if the song is any part of the shufflesongs above and if not to insert into the shufflesongs array in place of a duplicate.

This is what I have so far… any idea or suggestions?
/*a for loop to check if the songs in songs list are in the Shufflesongs and if not… put in the list somewhere.
for (let j= 0; j < this._songs.length; j++){
let counter=0;
for (let k=0; k < this._songs.length; k++){
if (this._songs[j]= Shufflesongs[k])
{counter++};

1 Like

Not sure what this line is about. It defines an array with a single number as its only element.

Please post a link to the exercise so we can refer to the instructions.

Is this the exercise?

Build a Library

1 Like

Sorry, iterating thru the problem & tinkering with it.

That is the exercise yes. Thanks hope blue skies are visible in your neck of the woods as well. Beutiful weather.

2 Likes

Okay, good to know. I’ll go and take a look.

In your CD class, do you have a shuffle method? That’s all you need to call it since it is nicely confined to the class.

Given a list of titles,

let tracks = ['Track 1','Track 2','Track 3','Track 4','Track 5','Track 6','Track 7','Track 8','Track 9','Track 10','Track 11','Track 12',]

How could we shuffle the list in place without creating any more data structures?

One approach would be to iterate over the list from left to right for one variable,

for (let i = 0; i < tracks.length; i++) {
    //
}

In the loop generate a random number that does not equal to i.

do {
    j = Math.floor(Math.random() * tracks.length);
} while (j === i);
temp = tracks[i];
tracks[i] = tracks[j];
tracks[j] = temp;

That’s one approach, anyway. They are others, of course. Try adapting that code pattern to your shuffle method.

Mostly sunny, though today is cloudy. Still cool, though. Didn’t go above 4C today.

1 Like

It is an attempt to create an array with a set length. The new Array(arrayLength) constructor doesn’t look to work inside the shuffle method. It may not be necessary.

Basically trying to understand a way or get a sense of a way to pull randomly for the 1st set of CD tracks and insure you get one and just one in the Randomsong list thru for loops.

1 Like

I read the instructions to mean the sense was you didn’t want to alter the existing CD track listing, but generate a new playlist. So that’s thoughts behind. Will try that thanks .>

1 Like

Yes, it makes sense to keep the original track list intact. You could declare an array inside the shuffle method and make it a copy of self.tracks.

tracks = self.tracks.slice();

Then shuffle the copy and return it as a playlist. Still tossing around ideas…

Not necessary if we use a slice of the array. It will be same length.

When you just want an array of length N,

myArray = new Array(N)

All the elements will as yet be undefined but can be accessed by index to set the values.

1 Like

Cool, I may try that in a bit. Dealing with some practical stuff the last few weeks so haven’t messed with javascript codeacademy course in a bit. The .slice() method sounds like winner winner chicken dinner.

1 Like

Got it to work, thanks. It’s here. Fisher Yates shuffle from wikipedia guidance, Stackoverflow https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array/2450976#2450976 & your code

  shuffle() {
   let tracks = this._songs.slice()
    for (let i = this._songs.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [tracks[i], tracks[j]] = [tracks[j], tracks[i]];
    };
    return tracks;  
};

Obviously I’m stuck back in ES5 and forgot, or didn’t know that ES6 has variable swap. What I don’t get is why the expression is wrapped in square brackets. What am I missing?

Since variabls declared in a method are destroyed upon exit, it might be more fitting to declare i and j right at the start of the method. They won’t be const though.

shuffle () {
    let i, j;
    for (i = ... 
        j = ...
    }
    ...
}

Another question comes to mind… Is there a getter for songs? If so, then this method should make full use of it and drop the underscore notation. Everything the function does is READONLY so having the getter works into the schema of what we’re doing.

This is untested, but what your code would be refactored to under the above conditions.

shuffle () {
  let t = tracks = this.songs.slice();
  let i, j, k = t.length;
  for (i = k; i > 0; i--) {
    j = Math.floor(Math.random() * k);
      [t[i-1], t[j]] = [t[j], t[i-1]];
  }
  return tracks;
}

I’ll have to get into the exercise to test this, but you could have a go with it, too. Be sure to save your code off to the side in case this doesn’t work and you are unable to get it to work.


When it comes down to the data crunching I loathe verbosity, as evidenced by the above. Pay particular note to t. It is a direct reference to tracks so we didn’t need to express the hand-off from one to the other. They are both the same object.


Update

Tested and working as expected (after squaring away the brackets, D’oh!). Let me know, please, if you run into any error cases. Thanks.