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

时间:2018-05-25 19:56:06

标签: javascript arrays shuffle

我有一个看起来像这样的数组

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

我希望有一个优雅的功能,可以改变数组的内容但保持第一个或最后一个元素是固定的。类似于customShuffle(x)的东西会对数组进行洗牌,但会确保元素"A"位于第一个位置,而元素"E"将位于最后一个位置。所有其他元素都被洗牌了。

9 个答案:

答案 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;
&#13;
&#13;

否则,如果您想要选择第一个和最后一个元素,正如您在原始问题中指出的那样,您可以执行以下操作:

  1. 首先找到您想要在第一个和最后一个位置拥有的元素的索引:firstIndexlastIndex
  2. 如果存在这些元素(它们可能不存在),请从阵列中删除它们。
  3. 对其余元素应用改组算法(不需要随机播放firstlast)。
  4. 如果需要,将第一个和最后一个元素添加回原位。
  5. &#13;
    &#13;
    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;
    &#13;
    &#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)

你可以这样做。 firstlast参数是可选的。

检查是否传递first以及它是否在数组中。如果是,则将其从阵列中删除。对last执行相同操作。剩余阵列的随机索引。根据混洗索引以及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);将改组整个阵列 arr = shuffle(arr, 'A');会将A移到前面并将其余部分随机播放 arr = shuffle(arr, 'A', 'B');会将A移到前面,B移到最后,然后将其余部分移动。

谨慎提醒:虽然这种方法不适用,但由于采用splice方法,它仍然会改变原始数组。

答案 4 :(得分:2)

您可以先生成新的混洗数组,然后检查是否提供了第一个和最后一个参数,并将这些元素放在第一个和最后一个位置。

&#13;
&#13;
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;
&#13;
&#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;
    }