最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Revert to original array order after shuffle - Stack Overflow

programmeradmin1浏览0评论

I am building a music site in Angular where the user can shuffle the songs on click of a shuffle button. I can get the shuffle to work with the below code:

var shuffleArray = function(array) {
    var m = array.length, t, i;
    // While there remain elements to shuffle
    while (m) {
        // Pick a remaining element…
        i = Math.floor(Math.random() * m--);
        // And swap it with the current element.
        t = array[m];
        array[m] = array[i];
        array[i] = t;
    }
    return array;
}
$scope.shuffleThis = function(tracks){
    shuffleArray(tracks);
}

What I can't figure out is how to allow the user to revert to the original order without refreshing the page or calling for the original JSON response.

UPDATE:

So I went with the following code, essentially cloning the array in order to use it later, but I am encountering an issue. When I go to unshuffle the array (bind the $scope.tracks to the $scope.unshuffled) it is setting the $scope.tracks of the parent controller. The structure I currently have is: mainCtrl is set at the html tag and this is where the shuffle/unshuffle functions live. Then each page url has a controller. To give you some context, here is the site I am building...

www.beta.audiblecoffee

As you can see, if you start to play a song, the bottom player control appears. when you click the shuffle button once (bottom right), the songs shuffle. Then you click the shuffle button again, nothing happens... now if you select a top nav item (New, Popular, Shuffled, etc), the original ordered array will briefly appear, then the new $scope.tracks from that particular page's controller will overwrite the $scope.tracks from the unshuffle function. But if you click another top nav item, the same will happen. SO I guess my question is how can I set the unshuffled array to the child controller $scope.tracks?

var shuffleArray = function(array) {
    var m = array.length, t, i;
    // While there remain elements to shuffle
    while (m) {
        // Pick a remaining element…
        i = Math.floor(Math.random() * m--);

        // And swap it with the current element.
        t = array[m];
        array[m] = array[i];
        array[i] = t;
    }

    return array;
}


$scope.shuffleThis = function(tracks) {
    $scope.isShuffled = true;
    $scope.unshuffled = tracks.slice(0);
    shuffleArray(tracks);
    console.log(player.tracks);
}

$scope.unshuffleThis = function() {
    $scope.isShuffled = false;
    player.tracks = $scope.unshuffled;
    $scope.tracks = $scope.unshuffled;
}

I am building a music site in Angular where the user can shuffle the songs on click of a shuffle button. I can get the shuffle to work with the below code:

var shuffleArray = function(array) {
    var m = array.length, t, i;
    // While there remain elements to shuffle
    while (m) {
        // Pick a remaining element…
        i = Math.floor(Math.random() * m--);
        // And swap it with the current element.
        t = array[m];
        array[m] = array[i];
        array[i] = t;
    }
    return array;
}
$scope.shuffleThis = function(tracks){
    shuffleArray(tracks);
}

What I can't figure out is how to allow the user to revert to the original order without refreshing the page or calling for the original JSON response.

UPDATE:

So I went with the following code, essentially cloning the array in order to use it later, but I am encountering an issue. When I go to unshuffle the array (bind the $scope.tracks to the $scope.unshuffled) it is setting the $scope.tracks of the parent controller. The structure I currently have is: mainCtrl is set at the html tag and this is where the shuffle/unshuffle functions live. Then each page url has a controller. To give you some context, here is the site I am building...

www.beta.audiblecoffee.

As you can see, if you start to play a song, the bottom player control appears. when you click the shuffle button once (bottom right), the songs shuffle. Then you click the shuffle button again, nothing happens... now if you select a top nav item (New, Popular, Shuffled, etc), the original ordered array will briefly appear, then the new $scope.tracks from that particular page's controller will overwrite the $scope.tracks from the unshuffle function. But if you click another top nav item, the same will happen. SO I guess my question is how can I set the unshuffled array to the child controller $scope.tracks?

var shuffleArray = function(array) {
    var m = array.length, t, i;
    // While there remain elements to shuffle
    while (m) {
        // Pick a remaining element…
        i = Math.floor(Math.random() * m--);

        // And swap it with the current element.
        t = array[m];
        array[m] = array[i];
        array[i] = t;
    }

    return array;
}


$scope.shuffleThis = function(tracks) {
    $scope.isShuffled = true;
    $scope.unshuffled = tracks.slice(0);
    shuffleArray(tracks);
    console.log(player.tracks);
}

$scope.unshuffleThis = function() {
    $scope.isShuffled = false;
    player.tracks = $scope.unshuffled;
    $scope.tracks = $scope.unshuffled;
}
Share Improve this question edited Feb 24, 2015 at 23:29 jeanhules asked Feb 24, 2015 at 16:07 jeanhulesjeanhules 2355 silver badges16 bronze badges 1
  • 7 Save a copy of the original data and shuffle a clone of it. – Vinay K Commented Feb 24, 2015 at 16:10
Add a ment  | 

5 Answers 5

Reset to default 3

The idea here is to use an intermediate reference and never actually modify the original playlist

var originalArray = [1,2,3];
var playlist = originalArray;

function shufflePlaylist() {
    playlist = shuffleArray(originalArray.slice());
}

function restoreOriginalPlaylist() {
    playlist = originalArray;
}

As a side note: this is not really an angular thing, you'll just have to bind it to scope afterwards.

You can:

  1. keep a reference to the original array and shuffle a copy each time:

    var originalTracks = ...
    
    $scope.shuffleThis = function(tracks) {
        shuffleArray(originalTracks.slice(0));
    };
    
  2. return a copy of the array from the function:

    var shuffleArray = function(array) {
        var m = array.length, t, i;
        array = array.slice(0);
        ...
    };
    

You could add a property "shuffledIndex" to every item and filter the list based on this index (with angular's filter orderBy, see https://docs.angularjs/api/ng/filter/orderBy).

This prevent you from storing 2 lists : the original and the shuffled one.

var shuffleArray = function(array) {
var m = array.length, t, i;

// While there remain elements to shuffle
while (m) {
    // Pick a remaining element…
    i = Math.floor(Math.random() * m--);

    array[m].shuffledIndex = i;
}

return $filter('orderBy')(array, 'shuffledIndex');
}

Why don't you leave the original array where it is, and gen a random number between 0 and the length of the array - 1?

array = ['test1','test2','test3','test4']
getRandomResult = function(){
  var randomIndex = Math.floor(Math.random() * array.length - 1) + 1
  var item = array[randomIndex];
  array.splice(randomIndex, 1) //remove to have the possibility for the same song twice in a row
  return item;
}

this way you don't have to duplicate it and you don't have to reorder it.

Alternatively you could do this

array = ['test1','test2','test3','test4']
indexes = []
for(var i = 0; i < array.length; i++){
  indexes.push(i)
}
indexes = shuffleArray(indexes); //your original function

then just pull take the first index out and grab the song at that index.

This does take a little more memory, but at least your not duplicating the full original array.

$scope.shuffleThis = function(tracks) {
    $scope.unshuffled = tracks.slice(0);
    shuffleArray(tracks);
}

Or, if you don't want to save the original on your $scope:

var unshuffled;
$scope.shuffleThis = function(tracks) {
    unshuffled = tracks.slice(0);
    shuffleArray(tracks);
}

Actually, I think in general it's really better to return a clone rather than modify the original; the latter is really more of a side-effect and would require careful documentation in practical application:

function shuffle(array) {
    var m = array.length, t, i;
    array = array.slice(0);
    // While there remain elements to shuffle
    while (m) {
        // Pick a remaining element…
        i = Math.floor(Math.random() * m--);
        // And swap it with the current element.
        t = array[m];
        array[m] = array[i];
        array[i] = t;
    }
    return array;
}

I'm also not really sure why you don't just set $scope.shuffleThis = shuffleArray, but that's up to you.

发布评论

评论列表(0)

  1. 暂无评论