Обмен всех элементов массива, кроме первого и последнего - PullRequest
0 голосов
/ 25 мая 2018

У меня есть массив, который выглядит следующим образом

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

Я хочу иметь элегантную функцию, которая бы перемешивала содержимое массива, но сохраняла первый или последний элемент фиксированным.Нечто подобное customShuffle(x), которое будет перетасовывать массив, но гарантирует, что элемент "A" будет в первой позиции, а элемент "E" будет в последней позиции.Все остальные элементы перемешиваются.

Ответы [ 9 ]

0 голосов
/ 25 мая 2018

Попробуйте что-нибудь подобное.Он сохраняет первый и последний элементы на месте без явного определения их значений и создает новый массив со случайным образом перемешанными другими элементами.

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;
}
0 голосов
/ 25 мая 2018

Поскольку вы просили элегантного, мне нравится реализовывать более функциональный стиль программирования здесь.Код ниже делает то, что вы хотите.Вы добавляете функцию 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"]

Я надеюсь, что это то, что вы ищете, и отвечает на ваш вопрос.

Редактировать

Оказывается, вы можете получить логику перемешивания всего в одну строку (при удалении ненужных новых строк).Когда вы добавляете две строки, чтобы сохранить первый или последний символ, вы можете создать эту функцию с помощью трех строк кода.

0 голосов
/ 25 мая 2018

Пожалуйста, попробуйте следующее простое решение. Это перетасует все элементы, кроме первого и последнего элемента массива ( 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;
}

Дальнейшее чтение:

0 голосов
/ 25 мая 2018

Если первый и последний элементы массива всегда остаются в одном и том же месте, вы можете применить обычный алгоритм перетасовки, такой как современный вариант Фишера и Йетса , пропуская эти позиции:

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

В противном случае, если вы хотите выбрать первый и последний элементы, как вы указали в исходном вопросе, вы можете сделать что-то вроде этого:

  1. Найдите индекс элементов, которые вы хотите иметь в первой и последней позициях: firstIndex и lastIndex.
  2. Если эти элементы существуют (они могут отсутствовать),удалите их из массива.
  3. Примените алгоритм перемешивания к оставшимся элементам (нет необходимости также перемешивать first и last).
  4. Добавьте первый и последний элементы обратно вих место, если вам нужно.

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;
}
0 голосов
/ 25 мая 2018

Сначала вы можете сгенерировать новый перемешанный массив, а затем проверить, предоставлены ли первый и последний аргументы, взять эти элементы и поместить их в первую и последнюю позиции.

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"))
0 голосов
/ 25 мая 2018

Вы можете сделать это так.Параметры 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.

0 голосов
/ 25 мая 2018

Использование алгоритма перемешивания из Как рандомизировать (перемешать) массив JavaScript?

Вы можете расширить его следующим образом:

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);
}
0 голосов
/ 25 мая 2018

Вы можете использовать эту функцию, которая использует современную версию алгоритма тасования Фишера-Йейтса , чтобы перетасовать подмассив 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));
0 голосов
/ 25 мая 2018
    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;
    }
...