我有一个这样的数组:

var arr1 = ["a", "b", "c", "d"];

我如何随机化/打乱它?


当前回答

使用ES6功能的现代短内联解决方案:

['a','b','c','d'].map(x => [Math.random(), x]).sort(([a], [b]) => a - b).map(([_, x]) => x);

(出于教育目的)

其他回答

可以(但不应该)将其用作Array中的原型:

来自ChristopheD:

Array.prototype.shuffle = function() {
  var i = this.length, j, temp;
  if ( i == 0 ) return this;
  while ( --i ) {
     j = Math.floor( Math.random() * ( i + 1 ) );
     temp = this[i];
     this[i] = this[j];
     this[j] = temp;
  }
  return this;
}
//doesn change array
Array.prototype.shuffle = function () {
    let res = [];
    let copy = [...this];

    while (copy.length > 0) {
        let index = Math.floor(Math.random() * copy.length);
        res.push(copy[index]);
        copy.splice(index, 1);
    }

    return res;
};

let a=[1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(a.shuffle());

无序排列到位

function shuffleArr (array){
    for (var i = array.length - 1; i > 0; i--) {
        var rand = Math.floor(Math.random() * (i + 1));
        [array[i], array[rand]] = [array[rand], array[i]]
    }
}

ES6纯,迭代

const getShuffledArr = arr => {
    const newArr = arr.slice()
    for (let i = newArr.length - 1; i > 0; i--) {
        const rand = Math.floor(Math.random() * (i + 1));
        [newArr[i], newArr[rand]] = [newArr[rand], newArr[i]];
    }
    return newArr
};

可靠性和性能测试

本页上的一些解决方案不可靠(它们只是部分随机化了阵列)。其他解决方案的效率明显较低。使用testShuffleArrayFun(见下文),我们可以测试阵列洗牌功能的可靠性和性能。

function testShuffleArrayFun(getShuffledArrayFun){
    const arr = [0,1,2,3,4,5,6,7,8,9]

    var countArr = arr.map(el=>{
        return arr.map(
            el=> 0
        )
    }) //   For each possible position in the shuffledArr and for 
       //   each possible value, we'll create a counter. 
    const t0 = performance.now()
    const n = 1000000
    for (var i=0 ; i<n ; i++){
        //   We'll call getShuffledArrayFun n times. 
        //   And for each iteration, we'll increment the counter. 
        var shuffledArr = getShuffledArrayFun(arr)
        shuffledArr.forEach(
            (value,key)=>{countArr[key][value]++}
        )
    }
    const t1 = performance.now()
    console.log(`Count Values in position`)
    console.table(countArr)

    const frequencyArr = countArr.map( positionArr => (
        positionArr.map(  
            count => count/n
        )
    )) 

    console.log("Frequency of value in position")
    console.table(frequencyArr)
    console.log(`total time: ${t1-t0}`)
}

其他解决方案

其他解决方案只是为了好玩。

ES6纯,递归

const getShuffledArr = arr => {
    if (arr.length === 1) {return arr};
    const rand = Math.floor(Math.random() * arr.length);
    return [arr[rand], ...getShuffledArr(arr.filter((_, i) => i != rand))];
};

ES6纯使用array.map

function getShuffledArr (arr){
    return [...arr].map( (_, i, arrCopy) => {
        var rand = i + ( Math.floor( Math.random() * (arrCopy.length - i) ) );
        [arrCopy[rand], arrCopy[i]] = [arrCopy[i], arrCopy[rand]]
        return arrCopy[i]
    })
}

ES6纯使用array.reduce

function getShuffledArr (arr){
    return arr.reduce( 
        (newArr, _, i) => {
            var rand = i + ( Math.floor( Math.random() * (newArr.length - i) ) );
            [newArr[rand], newArr[i]] = [newArr[i], newArr[rand]]
            return newArr
        }, [...arr]
    )
}

不改变源数组的shuffle函数

更新:这里我建议使用一种相对简单(不是从复杂性角度)和较短的算法,它可以很好地处理小型阵列,但在处理大型阵列时,它的成本肯定要比经典的Durstenfeld算法高得多。你可以在对这个问题的回答中找到杜斯滕菲尔德。

原答覆:

如果您不希望shuffle函数改变源数组,可以将其复制到本地变量,然后使用简单的shuffle逻辑完成其余操作。

function shuffle(array) {
  var result = [], source = array.concat([]);

  while (source.length) {
    let index = Math.floor(Math.random() * source.length);
    result.push(source[index]);
    source.splice(index, 1);
  }

  return result;
}

疏解逻辑:选取一个随机索引,然后将相应的元素添加到结果数组中,然后从源数组副本中删除它。重复此操作,直到源阵列变为空。

如果你真的想要简短的话,下面是我能做到的程度:

function shuffle(array) {
  var result = [], source = array.concat([]);

  while (source.length) {
    let index = Math.floor(Math.random() * source.length);
    result.push(source.splice(index, 1)[0]);
  }

  return result;
}

你可以使用lodash洗牌。就像一个魅力

import _ from lodash;

let numeric_array = [2, 4, 6, 9, 10];
let string_array = ['Car', 'Bus', 'Truck', 'Motorcycle', 'Bicycle', 'Person']

let shuffled_num_array = _.shuffle(numeric_array);
let shuffled_string_array = _.shuffle(string_array);

console.log(shuffled_num_array, shuffled_string_array)