How do I shuffle a Javascript Array ensuring each Index is in a new position in the new Array?

蹲街弑〆低调 提交于 2021-02-04 17:07:12

问题


I have an Array of Objects, like so.

var usersGoing = [
    { user: 0 },
    { user: 1 },
    { user: 2 },
    { user: 3 },
    { user: 4 }
];

I need to shuffle this Array so that no Object remains in the same index as when it was instantiated, like so:

[
    { user: 3 },
    { user: 2 },
    { user: 4 },
    { user: 0 },
    { user: 1 }
]

It is IMPERATIVE that the resulting array be sorted in this manner, as each of these user Objects will be assigned to a different user Object.

I have tried a few different sorting algorithms, including Fisher-Yates, and I've tried using Underscore.js' _.shuffle(), and this variant from Kirupa Shuffling an Array in JavaScript:

function shuffleFY(input) {
    for (var i = input.length-1; i >=0; i--) {
        var randomIndex = Math.floor(Math.random()*(i+1)); 
        var itemAtIndex = input[randomIndex]; 

        input[randomIndex] = input[i]; 
        input[i] = itemAtIndex;
    }
    return input;
}

Nothing I've tried is working. Help?

UPDATED: I've marked an answer as correct below, as the key points of the Sattolo Cycle were followed correctly. Also, this is NOT a duplicate of Shuffles Random Numbers with no repetition in Javascript/PHP as this question has the additional requirement of the resulting array not only not containing duplicates, but also cannot contain items in their same initial index position.


回答1:


You posted a link with Sattolo's algorithm in Python:

from random import randrange

def sattoloCycle(items):
    i = len(items)
    while i > 1:
        i = i - 1
        j = randrange(i)  # 0 <= j <= i-1
        items[j], items[i] = items[i], items[j]
    return

Here it is translated to JavaScript:

function sattoloCycle(items) {
  for(var i = items.length; i-- > 1; ) {
    var j = Math.floor(Math.random() * i);
    var tmp = items[i];
    items[i] = items[j];
    items[j] = tmp;
  }
}



回答2:


For each position, randomly pick an index at a higher position and swap the two.

Each object will either be in its own position and swapped out and have its original position locked, or it will be swapped into a lower position and locked into place by the time its position is up for replacement.

When you get to the second to last position, you will guarantee swap out for the last position (which may or may not be the same value as was originally there), and you're done. Nothing left to do for the final position.

1 2 3 4 5 - original vaues

3 2 1 4 5

3 1 2 4 5

3 1 4 2 5

3 1 4 5 2




回答3:


try this Fisher-Yates-Durstenfeld shuffle:

var usersGoing = [
    { user: 0 },
    { user: 1 },
    { user: 2 },
    { user: 3 },
    { user: 4 }
];


shuffle(usersGoing);
function shuffle(sourceArray) {
    for (var n = 0; n < sourceArray.length - 1; n++) {
        var k = n + Math.floor(Math.random() * (sourceArray.length - n));

        var temp = sourceArray[k];
        sourceArray[k] = sourceArray[n];
        sourceArray[n] = temp;
    }
}

console.log(usersGoing);



回答4:


Bit outdated answer, probably your software is finished, packed and sold by now but there's better way to achieve this...

const arr = [1,2,3,4,5,6,7,8,9];
const sfl = arr.sort( () => { Math.random() - .5 } );
// sfl == [2,9,5,1,3,6,...]


来源:https://stackoverflow.com/questions/33604137/how-do-i-shuffle-a-javascript-array-ensuring-each-index-is-in-a-new-position-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!