JavaScript实现循环从数组随机取值且相同位置元素不重复
实现方案
你需要的是数组的错排(任意元素不出现在原索引位置的随机排列),以下是两种可直接运行的实现方式:
方式1:改造洗牌算法(效率更高)
// 原数组 const colors = ["RED", "BLUE", "WHITE", "BLACK", "LIME", "YELLOW"]; // 生成单个错排序列 function generateDerangement(arr) { const result = [...arr]; const len = result.length; // Fisher-Yates 洗牌算法变体,交换时规避元素回到原位置 for (let i = len - 1; i > 0; i--) { let j = Math.floor(Math.random() * (i + 1)); // 校验:避免同索引交换、避免交换后两个位置都出现和原数组重合的情况 while (j === i || result[j] === arr[i] || result[i] === arr[j]) { j = Math.floor(Math.random() * (i + 1)); } [result[i], result[j]] = [result[j], result[i]]; } // 兜底校验首位,覆盖边界场景 if (result[0] === arr[0]) { const swapIdx = Math.floor(Math.random() * (len - 1)) + 1; [result[0], result[swapIdx]] = [result[swapIdx], result[0]]; } return result; } // 循环生成5个符合要求的序列 const output = []; for (let i = 0; i < 5; i++) { output.push(generateDerangement(colors)); } // 打印结果 output.forEach((item, index) => { console.log(`第${index + 1}个序列:${item.join(', ')}`); });
方式2:校验重试实现(逻辑更简单,适合短数组)
如果数组长度较短(比如你当前只有6个元素),可以用更直白的实现,生成随机排列后校验是否符合要求,不符合就重试:
const colors = ["RED", "BLUE", "WHITE", "BLACK", "LIME", "YELLOW"]; // 普通随机打乱数组 function shuffle(arr) { const res = [...arr]; for (let i = res.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [res[i], res[j]] = [res[j], res[i]]; } return res; } // 校验是否满足任意位置和原数组不重合的要求 function checkValid(arr, original) { return arr.every((item, idx) => item !== original[idx]); } // 生成5个有效序列 const resultList = []; while (resultList.length < 5) { const temp = shuffle(colors); if (checkValid(temp, colors)) { resultList.push(temp); } } // 输出 resultList.forEach((item, idx) => { console.log(`序列${idx + 1}:${item.join(', ')}`); });
效果验证
两种方式生成的所有序列,都不会出现和原数组同位置元素重合的情况,完全符合你给出的示例规则。
内容的提问来源于stack exchange,提问作者Marian Prekop
相关产品推荐
相关产品推荐

