我有一个看起来像这样的数组
const x = ['A','B','C','D','E']
我希望有一个优雅的功能,可以改变数组的内容但保持第一个或最后一个元素是固定的。类似于customShuffle(x)
的东西会对数组进行洗牌,但会确保元素"A"
位于第一个位置,而元素"E"
将位于最后一个位置。所有其他元素都被洗牌了。
答案 0 :(得分:3)
使用How to randomize (shuffle) a JavaScript array?
中的随机播放算法您可以像这样扩展它:
function shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
function customShuffle(array, first, last) {
if (first) {
if (last) {
const updatedArray = shuffle(array).filter(item => item !== first && item !== last);
return [first, ...updatedArray, last];
}
const updatedArray = shuffle(array).filter(item => item !== first);
return [first, ...updatedArray];
}
return shuffle(array);
}
答案 1 :(得分:3)
如果数组的第一个和最后一个元素始终保持在同一个位置,则可以应用正常的混洗算法,如Fisher and Yates'的现代变体,跳过这些位置:
function customShuffle(arr) {
if (arr.length < 3) {
return arr;
}
// Note the -2 (instead of -1) and the i > 1 (instead of i > 0):
for (let i = arr.length - 2; i > 1; --i) {
const j = 1 + Math.floor(Math.random() * i);
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}
console.log(customShuffle([1, 2, 3, 4, 5]).join(', '));
console.log(customShuffle(['A', 'B', 'C', 'D', 'E']).join(', '));
&#13;
.as-console-wrapper {
max-height: 100vh;
}
&#13;
否则,如果您想要选择第一个和最后一个元素,正如您在原始问题中指出的那样,您可以执行以下操作:
firstIndex
和lastIndex
。first
和last
)。
function customShuffle(arr, first, last) {
// Find and remove first and last:
const firstIndex = arr.indexOf(first);
if (firstIndex !== -1) arr.splice(firstIndex, 1);
const lastIndex = arr.indexOf(last);
if (lastIndex !== -1) arr.splice(lastIndex, 1);
// Normal shuffle with the remainign elements using ES6:
for (let i = arr.length - 1; i > 0; --i) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
// Add them back in their new position:
if (firstIndex !== -1) arr.unshift(first);
if (lastIndex !== -1) arr.push(last);
return arr;
}
console.log(customShuffle([1, 2, 3, 4, 5], 5, 1).join(', '));
console.log(customShuffle(['A', 'B', 'C', 'D', 'E'], 'E', 'C').join(', '));
console.log(customShuffle([1, 2, 3, 4, 5], 10, 20).join(', '));
&#13;
.as-console-wrapper {
max-height: 100vh;
}
&#13;
答案 2 :(得分:2)
您可以使用此功能使用the modern version of the Fisher–Yates shuffle algorithm来重新排列子阵列x.slice(1, x.length - 1)
,x
除去第一个和最后一个元素,然后将它们添加回改组子阵列:
const x = ['A','B','C','D','E'];
function customShuffle(x) {
var y = x.slice(1, x.length - 1);
var j, t, i;
for (i = y.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
t = y[i];
y[i] = y[j];
y[j] = t;
}
return [x[0]].concat(y).concat(x[x.length-1]);
}
console.log(customShuffle(x));
console.log(customShuffle(x));
console.log(customShuffle(x));
console.log(customShuffle(x));
答案 3 :(得分:2)
你可以这样做。 first
和last
参数是可选的。
检查是否传递first
以及它是否在数组中。如果是,则将其从阵列中删除。对last
执行相同操作。剩余阵列的随机索引。根据混洗索引以及first
和last
参数重新创建新数组。
const shuffle = (arr, first, last) => {
let firstIn = false;
let lastIn = false;
if (first && arr.includes(first)) {
arr.splice(arr.indexOf(first), 1);
firstIn = true;
}
if (last && arr.includes(last)) {
arr.splice(arr.indexOf(last), 1);
lastIn = true;
}
const len = arr.length;
const used = [];
while (used.length !== len) {
let r = Math.floor(Math.random() * len);
if (!used.includes(r)) { used.push(r); }
}
const newArr = [];
if (first && firstIn) { newArr.push(first); }
for (let i = 0; i < len; i++) {
newArr.push(arr[used[i]]);
}
if (last && lastIn) { newArr.push(last); }
return newArr;
}
let arr = ['A', 'B', 'C', 'D', 'F'];
arr = shuffle(arr);
console.log(arr);
arr = shuffle(arr, 'A');
console.log(arr);
arr = shuffle(arr, 'A', 'B');
console.log(arr);
shuffle(arr);
将改组整个阵列
arr = shuffle(arr, 'A');
会将A
移到前面并将其余部分随机播放
arr = shuffle(arr, 'A', 'B');
会将A
移到前面,B
移到最后,然后将其余部分移动。
谨慎提醒:虽然这种方法不适用,但由于采用splice
方法,它仍然会改变原始数组。
答案 4 :(得分:2)
您可以先生成新的混洗数组,然后检查是否提供了第一个和最后一个参数,并将这些元素放在第一个和最后一个位置。
const x = ['A', 'B', 'C', 'D', 'E']
function shuffle(arr, first, last) {
const newArr = arr.reduce((r, e, i) => {
const pos = parseInt(Math.random() * (i + 1))
r.splice(pos, 0, e)
return r;
}, []);
if (first) newArr.unshift(newArr.splice(newArr.indexOf(first), 1)[0]);
if (last) newArr.push(newArr.splice(newArr.indexOf(last), 1)[0])
return newArr
}
console.log(shuffle(x))
console.log(shuffle(x, "A", "E"))
&#13;
答案 5 :(得分:2)
请尝试以下简单的解决方案。这将洗去除数组的第一个和最后一个元素(jsfiddle)以外的所有元素:
const x = ['A', 'B', 'C', 'D', 'E'];
CustomShuffle(x);
function CustomShuffle(x) {
//shuffle the elements in between first and the last
var max = x.length - 2;
var min = 1;
for (var i = max; i >= min; i--) {
var randomIndex = Math.floor(Math.random() * (max - min + 1)) + min;
var itemAtIndex = x[randomIndex];
x[randomIndex] = x[i];
x[i] = itemAtIndex;
}
alert(x);
}
如果事先没有第一个和最后一个元素,您可以尝试以下方法(jsfiddle):
const x = ['A', 'B', 'C', 'D', 'E'];
CustomShuffle(x, first = "B", last = "A");
function CustomShuffle(x, first, last) {
//position first element correctly
var indexToSwap = x.indexOf(first);
if (indexToSwap != 0) {
x = SwapValuesAtIndices(x, indexToSwap, 0);
}
//position last element correctly
indexToSwap = x.indexOf(last);
if (indexToSwap != x.length - 1) {
x = SwapValuesAtIndices(x, indexToSwap, x.length - 1);
}
//randomly shuffle the remaining elements in between
var max = x.length - 2;
var min = 1;
for (var i = max; i >= min; i--) {
var randomIndex = Math.floor(Math.random() * (max - min + 1)) + min;
var itemAtIndex = x[randomIndex];
x[randomIndex] = x[i];
x[i] = itemAtIndex;
}
alert(x);
}
function SwapValuesAtIndices(array, firstIndex, secondIndex) {
var temp = array[firstIndex];
array[firstIndex] = array[secondIndex];
array[secondIndex] = temp;
return array;
}
进一步阅读:
答案 6 :(得分:2)
尝试这样的事情。它保留第一个和最后一个元素而不显式定义它们的值,并构建一个新数组,其他元素随机混合。
const x = ['A','B','C','D','E'];
const shuffledArray = customShuffle(x);
console.log(shuffledArray);
function customShuffle(arr) {
let newArray = [];
const first = arr[0];
const last = arr[arr.length-1];
//First, remove the 'first' and 'last' values from array:
for(let i=0; i<arr.length; i++){
if(arr[i] == first || arr[i] == last){
arr.splice(i, 1);
}
}
//Next, add values to the new array at random:
for(let i=0; i<arr.length; i++){
const indexToRemove = Math.floor( Math.random() * arr.length );
const value = arr[indexToRemove];
arr.splice(indexToRemove, 1);
newArray.push(value);
}
//Last, add in the 'first' and 'last' values:
newArray.unshift(first);
newArray.push(last);
return newArray;
}
答案 7 :(得分:2)
因为你要求优雅,我喜欢在这里实现更具功能性的编程风格。下面的代码可以满足您的需求。你使用你的数组补充name=
函数,你希望它被洗牌的最大次数(数字越大,洗牌越好),shuffle
保持第一个元素到位,{{ {1}}保留最后一个。
true
使用示例:
false
输出:function shuffle(array, maxTimes, first) {
var temp = (first) ? array.reverse().pop() : array.pop();
Array.from(
Array(Math.round(Math.random()*maxTimes))
.keys()).forEach(val => array = array.reduce((acc,val) =>
(Math.random() > 0.5) ? acc.concat([val]) : [val].concat(acc),[]));
return (first) ? [temp].concat(array.reverse()) : array.concat([temp]);
}
我希望这是你正在寻找的并回答你的问题。
修改强>
事实证明,您可以在一个行中获取随机逻辑(删除不必要的换行符时)。当您添加两行以保留第一个或最后一个字符时,您实际上可以使用三个代码行创建此函数。
答案 8 :(得分:-1)
function SpecialShuffle(MyArray)
{
var newArray = [];
var counter= 1;
for(var i = MyArray.length-1 ; i>-1 ; i--)
{
if(i == MyArray.length)
{
newArray[i] = MyArray[i]
}
else if(i == 0 )
{
newArray[i]=MyArray[i];
}
else
{
newArray[counter] = MyArray[i];
counter++;
}
}
return newArray;
}