我有一个这样的数组:

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

我如何随机化/打乱它?


当前回答

Fisher Yates的这种变体稍微更有效,因为它避免了元素与自身的交换:

function shuffle(array) {
  var elementsRemaining = array.length, temp, randomIndex;
  while (elementsRemaining > 1) {
    randomIndex = Math.floor(Math.random() * elementsRemaining--);
    if (randomIndex != elementsRemaining) {
      temp = array[elementsRemaining];
      array[elementsRemaining] = array[randomIndex];
      array[randomIndex] = temp;
    }
  }
  return array;
}

其他回答

警告不建议将此答案用于随机化大型阵列、密码学或任何其他需要真正随机性的应用程序,因为其存在偏差且效率低下。元素的位置只是半随机的,它们将倾向于保持更接近其原始位置。看见https://stackoverflow.com/a/18650169/28234.


可以使用Math.random任意决定是否返回1:-1:

[1, 2, 3, 4].sort(() => (Math.random() > 0.5) ? 1 : -1)

尝试运行以下示例:

常量数组=[1,2,3,4];//基于Math.Random返回的值,//任意决定是否返回1:-1const shuffeled=array.sort(()=>{const randomTrueOrFalse=数学random()>0.5;return randomTrueOrFalse?1 : -1});console.log(shuffeled);

只是为了在馅饼里插一根手指。在这里,我介绍了Fisher Yates shuffle的递归实现(我认为)。它给出了统一的随机性。

注意:~~(双颚化符运算符)实际上与正实数的Math.floor()类似。这只是一条捷径。

var shuffle=a=>a.length?a.splice(~~(Math.random()*a.length),1).contat(shuffle(a)):a;console.log(JSON.stringify(shuffle([0,1,2,3,4,5,6,7,8,9]));

编辑:由于使用了.splice(),上面的代码是O(n^2),但我们可以通过交换技巧消除O(n)中的拼接和混洗。

var shuffle=(a,l=a.length,r=~~(Math.random()*l))=>l?([a[r],a[l-1]]=[a[l-1],a[r]],shuffle(a,l-1)):a;var arr=Array.from({length:3000},(_,i)=>i);console.time(“shuffle”);洗牌(arr);console.timeEnd(“shuffle”);

问题是,JS无法与大型递归合作。在这种特殊的情况下,数组大小会受到限制,大约为3000~7000,这取决于浏览器引擎和一些未知的事实。

对CoolAJ86答案的简单修改,不修改原始数组:

 /**
 * Returns a new array whose contents are a shuffled copy of the original array.
 * @param {Array} The items to shuffle.
 * https://stackoverflow.com/a/2450976/1673761
 * https://stackoverflow.com/a/44071316/1673761
 */
const shuffle = (array) => {
  let currentIndex = array.length;
  let temporaryValue;
  let randomIndex;
  const newArray = array.slice();
  // While there remains elements to shuffle...
  while (currentIndex) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;
    // Swap it with the current element.
    temporaryValue = newArray[currentIndex];
    newArray[currentIndex] = newArray[randomIndex];
    newArray[randomIndex] = temporaryValue;
  }
  return newArray;
};

我发现这个变体挂在“作者删除”的答案中,重复了这个问题。与其他一些已经获得许多支持的答案不同,这是:

实际上是随机的不到位(因此名称被打乱而不是打乱)此处尚未出现多个变体

这是一个jsfiddle,显示了它的使用情况。

Array.prototype.shuffled = function() {
  return this.map(function(n){ return [Math.random(), n] })
             .sort().map(function(n){ return n[1] });
}

我使用以下两种方法:

此方法不会修改原始数组

shuffle(array);

功能洗牌(arr){var len=arr.length;var d=长度;var数组=[];变量k,i;对于(i=0;i<d;i++){k=数学楼层(Math.random()*len);array.push(arr[k]);arr.splice(k,1);len=排列长度;}对于(i=0;i<d;i++){arr[i]=阵列[i];}返回arr;}var arr=[“a”,“b”,“c”,“d”];arr=洗牌(arr);控制台日志(arr);

此方法修改原始数组

array.shuffle();

Array.prototype.shuffle=函数(){var len=此长度;var d=长度;var数组=[];变量k,i;对于(i=0;i<d;i++){k=数学楼层(Math.random()*len);array.push(this[k]);此接头(k,1);len=此长度;}对于(i=0;i<d;i++){this[i]=数组[i];}}var arr=[“a”,“b”,“c”,“d”];arr.shuffle();控制台日志(arr);