【问题标题】:How do I shuffle a Javascript Array ensuring each Index is in a new position in the new Array?如何对 Javascript 数组进行洗牌,以确保每个索引都位于新数组中的新位置?
【发布时间】:2016-02-09 19:18:27
【问题描述】:

我有一个对象数组,就像这样。

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

我需要对这个 Array 进行洗牌,以便没有 Object 保留在与实例化时相同的索引中,如下所示:

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

必须以这种方式对结果数组进行排序,因为这些用户对象中的每一个都将分配给不同的用户对象。

我尝试了几种不同的排序算法,包括 Fisher-Yates,我尝试过使用 Underscore.js 的 _.shuffle(),以及来自 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;
}

我尝试过的任何方法都不起作用。帮忙?

更新:我在下面将答案标记为正确,因为正确遵循了 Sattolo 循环的关键点。此外,这不是 Shuffles Random Numbers with no repetition in Javascript/PHP 的重复,因为这个问题对结果数组有额外的要求,不仅不包含重复项,而且不能在相同的初始索引位置包含项目。

【问题讨论】:

  • 我相信我正在寻找的是一个代表 The Sattolo Cycle seen here 的 Javascript 函数。 THere's an example in Python there,但我对Python一无所知,不知道语法。
  • 将 Fisher-Yates-Durstenfeld-Knuth 转换为 Sattolo 就像将 Math.random()*(i+1) 更改为 Math.random()*(i) 一样简单

标签: javascript arrays underscore.js shuffle


【解决方案1】:

您在 Python 中发布了 Sattolo 算法的链接:

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

这里被翻译成 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】:

    对于每个位置,随机选择一个较高位置的索引并将两者交换。

    每个对象要么处于其自己的位置并换出并锁定其原始位置,要么将其换入较低的位置并在其位置准备好更换时锁定到位。

    当您到达倒数第二个位置时,您将保证换掉最后一个位置(可能与最初的位置相同,也可能不同),然后您就完成了。最终位置无事可做。

    1 2 3 4 5 - 原始值

    3 2 1 4 5

    3 1 2 4 5

    3 1 4 2 5

    3 1 4 5 2

    【讨论】:

      【解决方案3】:

      试试这个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】:

        @xaxxon 删除的答案是正确的。就“洗牌”一词而言,这不是一个有意义的请求。洗牌时,不能设置洗牌涉及随机性这样的限制条件。对于您想要的,只需旋转阵列即可。如果您现在对轮换不满意,您必须解释原因...

        【讨论】:

          【解决方案5】:

          有点过时的答案,可能您的软件现在已经完成,打包和销售,但有更好的方法来实现这一点......

          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,...]
          

          【讨论】:

          • 这并不能保证每个索引每次都在一个新的位置。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-15
          • 1970-01-01
          • 2018-01-31
          • 2021-12-17
          • 1970-01-01
          • 2013-06-28
          相关资源
          最近更新 更多