【问题标题】:Javacript: Is there a function that shuffles an array with every element switching places?Javascript:是否有一个函数可以在每个元素切换位置时对数组进行混洗?
【发布时间】:2023-01-15 10:53:05
【问题描述】:

我正在寻找一个函数,它不是简单地洗牌一个数组,而是洗牌而不在他之前所在的索引处留下任何元素。

我已经尝试过 Fisher-Yates 算法,但它并没有解决我的问题:

function shuffle(array) {
  var m = array.length, t, i;
  while (m) {
    i = Math.floor(Math.random() * m--);
    t = array[m];
    array[m] = array[i];
    array[i] = t;
  }
}

测试时,我得到了 [0, 1, 2, 3, 4, 5] 之类的结果改组为 [5, 0, 3, 1, 4, 2]。但在这里,4 几乎“停留”在与之前相同的指数上。

例如,我正在寻找的函数会将 [0, 1, 2, 3, 4, 5] 随机化为 [4, 1, 5, 3, 2],其中没有元素与之前的索引相同

【问题讨论】:

  • 2 在您的第一个示例中没有移动吗?我不清楚为什么 2 是个问题?在您的第二个示例中,0 发生了什么事?而不是 1 仍然和以前一样?
  • 如果“随机”不是您对“洗牌”的定义,那么您对“洗牌”的确切定义是什么?例如:简单地将每个元素向前移动一个索引(模长度)是否合格?
  • @NickParsons 是的,编辑了它,感谢您指出
  • @jsejcksn 理论上是合格的,但结果需要改变,我相信一段时间后它会重演
  • ^一段时间后它会重演“ @Ninjdai 任何算法最终都会重复:没有有限有序集合具有无限排列。您需要提供明确定义的期望才能获得令人满意的答案。

标签: javascript node.js arrays javascript-objects shuffle


【解决方案1】:

检查放在最右边(第一个未排序)位置的元素是否与原来的元素不一样。您还需要确保在最终交换中插入的内容不会导致无限循环 - 在循环结束后使用单独的条件。

function shuffle(array) {
  const originalArray = [...array];
  let m = array.length;
  while (m > 1) {
    let i;
    do {
      i = Math.floor(Math.random() * m);
    } while (array[i] === originalArray[m - 1]);
    m--;
    const t = array[m];
    array[m] = array[i];
    array[i] = t;
  }
  if (array[0] === originalArray[0]) {
    [array[0], [array[1]]] = [array[1], [array[0]]];
  }
  return array;
}
for (let i = 0; i < 100; i++) {
  console.log(shuffle([0, 1, 2, 3, 4, 5]));
}

【讨论】:

  • 太感谢了 !这几乎就是我想弄清楚的,而且它完全按照我的预期工作!
【解决方案2】:

使用哈希图,您可以跟踪每个数字存储的先前位置,然后生成一个随机索引,直到它与先前位置和已使用的任何其他索引不同为止。

一个极端情况是您放置的最后一个数字。由于只剩下 1 个位置,如果您之前为该号码分配了那个位置并尝试生成直到它是唯一的,那么它将不允许您移动到其他任何地方,因为所有其他索引都已被占用。因此,您必须求助于将那个保持在剩余位置。

let numberToIndexMap = {}

function shuffle(array) {
    var length = array.length;
    let currentNumIndex = length - 1
    let shuffledArray = []
    let indexesUsed = []

    while (currentNumIndex > -1) {
        let randIndex = Math.floor(Math.random() * length);
        let currentNum = array[currentNumIndex]

        if (Object.keys(numberToIndexMap)?.length > 0) {
            /*
            For the last number we are checking (at index 0) there is a paradox where you might need to select an index
            that hasn't been chosen but you already were in that spot last time. Unfortunately 
            that number has to stay in that spot unless it shuffles the rest of the numbers
            Otherwise you will choose a spot in the array that has either been used

            */

            if (currentNumIndex == 0) {
                while (indexesUsed.includes(randIndex)) {
                    randIndex = Math.floor(Math.random() * length);
                }
            } else {
                while (randIndex == numberToIndexMap[currentNum] || indexesUsed.includes(randIndex)) {
                    randIndex = Math.floor(Math.random() * length);
                }
            }
        }
        numberToIndexMap[currentNum] = randIndex
        indexesUsed.push(randIndex)
        shuffledArray[randIndex] = currentNum
        currentNumIndex--

    }
    return shuffledArray
}


function test() {
    let array = [1, 2, 3]
    for (let i = 0; i < 10; i++) {
        array = shuffle(array)
        console.log(array)
    }
}

test()

【讨论】:

    猜你喜欢
    • 2021-12-31
    • 1970-01-01
    • 1970-01-01
    • 2016-02-09
    • 2020-02-05
    • 1970-01-01
    • 2014-12-15
    • 2019-10-23
    • 2020-05-01
    相关资源
    最近更新 更多