交换数组中除 first 和 last 之外的所有元素
Swapping all elements of an array except for first and last
我有一个看起来像这样的数组
const x = ['A','B','C','D','E']
我想要一个优雅的函数来随机排列数组的内容,但保持第一个或最后一个元素固定。像 customShuffle(x)
这样的东西会打乱数组,但确保元素 "A"
位于第一个位置,元素 "E"
位于最后一个位置。所有其他元素都被打乱。
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;
}
您可以使用此函数,它使用 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));
使用 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);
}
你可以这样做。 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
方法,它仍会改变原始数组。
您可以先生成新的随机排列数组,然后检查是否提供了第一个和最后一个参数,然后将这些元素放在第一个和最后一个位置。
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"))
请尝试以下简单的 solution.This 将随机排列除数组的第一个和最后一个元素 (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);
}
如果 first 和 last 元素事先没有到位,您可以尝试以下 (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;
}
延伸阅读:
- Shuffling an array
- 生成给定的随机数
范围
- Swapping elements
如果数组的第一个和最后一个元素始终位于同一个位置,您可以应用正常的改组算法,如 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(', '));
.as-console-wrapper {
max-height: 100vh;
}
否则,如果您想选择第一个和最后一个元素,正如您在原始问题中指出的那样,您可以这样做:
- 首先在第一个和最后一个位置找到你想要的元素的索引:
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(', '));
.as-console-wrapper {
max-height: 100vh;
}
尝试这样的事情。它保留第一个和最后一个元素而不明确定义它们的值,并构建一个新数组,其他元素随机排列。
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;
}
因为你要求优雅,所以我喜欢在这里实现更函数式的编程风格。下面的代码做你想要的。你用你的数组来补充 shuffle
函数,你希望它洗牌的最大次数(数字越大,洗牌越好),以及 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]);
}
用法示例:
shuffle(['A','B','C','D','E'], 10, true);
输出:["A", "C", "D", "B", "E"]
我希望这就是您正在寻找的并能回答您的问题。
编辑
事实证明,您可以在 一个 行中获得全部随机播放逻辑(删除不必要的换行符时)。当您添加这两行以保留第一个或最后一个字符时,您基本上可以使用 三 行代码创建此函数。
我有一个看起来像这样的数组
const x = ['A','B','C','D','E']
我想要一个优雅的函数来随机排列数组的内容,但保持第一个或最后一个元素固定。像 customShuffle(x)
这样的东西会打乱数组,但确保元素 "A"
位于第一个位置,元素 "E"
位于最后一个位置。所有其他元素都被打乱。
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;
}
您可以使用此函数,它使用 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));
使用 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);
}
你可以这样做。 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
方法,它仍会改变原始数组。
您可以先生成新的随机排列数组,然后检查是否提供了第一个和最后一个参数,然后将这些元素放在第一个和最后一个位置。
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"))
请尝试以下简单的 solution.This 将随机排列除数组的第一个和最后一个元素 (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);
}
如果 first 和 last 元素事先没有到位,您可以尝试以下 (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;
}
延伸阅读:
- Shuffling an array
- 生成给定的随机数 范围
- Swapping elements
如果数组的第一个和最后一个元素始终位于同一个位置,您可以应用正常的改组算法,如 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(', '));
.as-console-wrapper {
max-height: 100vh;
}
否则,如果您想选择第一个和最后一个元素,正如您在原始问题中指出的那样,您可以这样做:
- 首先在第一个和最后一个位置找到你想要的元素的索引:
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(', '));
.as-console-wrapper {
max-height: 100vh;
}
尝试这样的事情。它保留第一个和最后一个元素而不明确定义它们的值,并构建一个新数组,其他元素随机排列。
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;
}
因为你要求优雅,所以我喜欢在这里实现更函数式的编程风格。下面的代码做你想要的。你用你的数组来补充 shuffle
函数,你希望它洗牌的最大次数(数字越大,洗牌越好),以及 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]);
}
用法示例:
shuffle(['A','B','C','D','E'], 10, true);
输出:["A", "C", "D", "B", "E"]
我希望这就是您正在寻找的并能回答您的问题。
编辑
事实证明,您可以在 一个 行中获得全部随机播放逻辑(删除不必要的换行符时)。当您添加这两行以保留第一个或最后一个字符时,您基本上可以使用 三 行代码创建此函数。