简体   繁体   English

交换除第一个和最后一个数组之外的所有数组元素

[英]Swapping all elements of an array except for first and last

I have an array that looks like this 我有一个看起来像这样的数组

const x = ['A','B','C','D','E']

I want to have an elegant function that would shuffle the content of the array but keeps the first or the last element fixed. 我希望有一个优雅的函数,可以改变数组的内容,但保持第一个或最后一个元素是固定的。 Something like customShuffle(x) which will shuffle the array but ensures that the element "A" will be in the first position and the element "E" will be at the last position. customShuffle(x)类的东西customShuffle(x)数组进行洗牌,但确保元素"A"将位于第一个位置而元素"E"将位于最后一个位置。 All other elements are shuffled. 所有其他元素都被洗牌。

Using the shuffle algorithm from How to randomize (shuffle) a JavaScript array? 使用How to randomize(shuffle)JavaScript数组中的shuffle算法

You can extend it like this: 您可以像这样扩展它:

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);
}

If the first and last elements of the array always stay in that same place, you can apply a normal shuffling algorithm, like a modern variation of Fisher and Yates' , skipping those positions: 如果数组的第一个和最后一个元素始终保持在同一个位置,则可以应用正常的混洗算法,如Fisher和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; } 

Otherwise, if you want to choose the first and last elements, as you pointed out in your original question, you can do something like this: 否则,如果您要选择第一个和最后一个元素,正如您在原始问题中指出的那样,您可以执行以下操作:

  1. Find the index of the elements you want to have in the first and last positions first: firstIndex and lastIndex . 首先找到您想要在第一个和最后一个位置拥有的元素的索引: firstIndexlastIndex
  2. If those elements exist (they might not be present), remove them from the array. 如果存在这些元素(它们可能不存在),请从阵列中删除它们。
  3. Apply a shuffling algorithm to the remaining elements (there's no need to also shuffle first and last ). 套用洗牌算法,剩余的元素(有没有必要也洗牌firstlast )。
  4. Add the first and last elements back into their place, if you need to. 如果需要,将第一个和最后一个元素添加回原位。

 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; } 

You can use this function which uses the modern version of the Fisher–Yates shuffle algorithm to shuffle the sub-array x.slice(1, x.length - 1) , which is x with the exclusion of the first and last elements, then adds them back to the shuffled sub-array: 你可以使用这个函数,它使用现代版本的Fisher-Yates shuffle算法来重新排列子数组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)); 

You can do it like this. 你可以这样做。 first and last params are optional. firstlast参数是可选的。

Check if first is passed and if it is in the array. 检查是否first通过以及是否在数组中。 If so, then remove it from the array. 如果是,则将其从阵列中删除。 Do the same for the last . 做到last Shuffle indices of the remaining array. 剩余阵列的随机索引。 Recreate new array based on the shuffled indices, as well as first and last arguments. 基于混洗索引以及firstlast参数重新创建新数组。

 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); will shuffle the whole array. 将洗牌整个阵列。
arr = shuffle(arr, 'A'); will move A to the front and shuffle the rest. A移到前面并将其余部分洗牌。
arr = shuffle(arr, 'A', 'B'); will move A to the front, B to the end, and shuffle the rest. A移至前方, B移至末尾,并将其余移动。

Word of caution: while this approach is not in-place, it will still mutate the original array, because of the splice method. 注意事项:虽然这种方法不适用,但由于splice方法,它仍会改变原始数组。

You could first generate new shuffled array and then check if first and last arguments are provided and take those elements and place them on first and last position. 您可以先生成新的混洗数组,然后检查是否提供了第一个和最后一个参数,并将这些元素放在第一个和最后一个位置。

 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")) 

Please try the following simple solution.This will shuffle all the elements other than the first and the last element of the array ( jsfiddle ): 请尝试以下简单的解决方案。这将洗去除数组的第一个和最后一个元素( 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); } 

In case first and last elements are not in place beforehand, you may try the following ( jsfiddle ): 如果事先没有第一个和最后一个元素,您可以尝试以下( 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;
}

Further reading: 进一步阅读:

Try something like this. 尝试这样的事情。 It keeps the first and last elements in place without explicitly defining their values, and builds a new array with the other elements shuffled randomly. 它保留第一个和最后一个元素而不显式定义它们的值,并构建一个新的数组,其他元素随机混合。

 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; } 

Because you asked for elegant, I like to implement a more functional style of programming here. 因为你要求优雅,我喜欢在这里实现更具功能性的编程风格。 The code below does what you want. 下面的代码可以满足您的需求。 You supple the shuffle function with your array, the max number of times you want it shuffled (the higher the number, the better the shuffle is), and true to keep the first element in place, false to keep the last. 你柔顺的shuffle功能与你的数组,你要的倍最大的IT洗牌(数字越高,更好的洗牌),并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]);
}

Example usage: 用法示例:

shuffle(['A','B','C','D','E'], 10, true);

Output: ["A", "C", "D", "B", "E"] 输出: ["A", "C", "D", "B", "E"]

I hope this is what you're looking for and answers your question. 我希望这是你正在寻找的并回答你的问题。

Edit 编辑

Turns out you can get the shuffle logic all in one line (when removing the unnecessary newlines). 原来,你可以得到所有在一行洗牌逻辑(在去除不需要换行符时)。 When you add the two lines to retain the first or last character, you can essentially create this function with three lines of code. 当您添加两行保留第一个或最后一个字符,你基本上可以用三行代码创建此功能。

    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;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM