Переместить элемент массива из одной позиции массива в другую - PullRequest
426 голосов
/ 15 марта 2011

Мне трудно понять, как переместить элемент массива.Например, с учетом следующего:

var arr = [ 'a', 'b', 'c', 'd', 'e'];

Как написать функцию для перемещения 'd' до 'b'?

или 'a' после 'c'?

После перемещения индексы остальных элементов должны быть обновлены.Это означает, что в первом примере после хода arr [0] будет = 'a', arr [1] = 'd' arr [2] = 'b', arr [3] = 'c', arr [4] ='e'

Кажется, это должно быть довольно просто, но я не могу обернуться вокруг него.

Ответы [ 21 ]

596 голосов
/ 15 марта 2011

Если вы хотите версию на npm, array-move является наиболее близким к этому ответу, хотя это не та же реализация.Смотрите его использование раздел для более подробной информации.Предыдущая версия этого ответа (которая изменила Array.prototype.move) может быть найдена на npm в array.prototype.move .


. У меня был довольно хороший успех с этой функцией:

function array_move(arr, old_index, new_index) {
    if (new_index >= arr.length) {
        var k = new_index - arr.length + 1;
        while (k--) {
            arr.push(undefined);
        }
    }
    arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
    return arr; // for testing
};

// returns [2, 1, 3]
console.log(array_move([1, 2, 3], 0, 1)); 

Обратите внимание, что последний return просто для целей тестирования: splice выполняет операции с массивом на месте, поэтому возвратне обязательно.Таким образом, move является операцией на месте.Если вы хотите избежать этого и вернуть копию, используйте slice.

Пошаговый код:

  1. Если new_index больше, чемдлина массива, мы хотим (я полагаю) правильно заполнить массив новыми undefined с.Этот небольшой фрагмент обрабатывает это, нажимая undefined на массив, пока мы не получим нужную длину.
  2. Затем, в arr.splice(old_index, 1)[0], мы склеиваем старый элемент.splice возвращает элемент, который был вставлен, но он находится в массиве.В нашем примере выше это было [1].Итак, мы берем первый индекс этого массива, чтобы получить туда 1.
  3. Затем мы используем splice, чтобы вставить этот элемент вместо new_index.Поскольку мы добавили массив выше, если new_index > arr.length, он, вероятно, появится в нужном месте, если они не сделали что-то странное, например, передают отрицательное число.

Более интересная версия для учета отрицательных показателей:

function array_move(arr, old_index, new_index) {
    while (old_index < 0) {
        old_index += arr.length;
    }
    while (new_index < 0) {
        new_index += arr.length;
    }
    if (new_index >= arr.length) {
        var k = new_index - arr.length + 1;
        while (k--) {
            arr.push(undefined);
        }
    }
    arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
    return arr; // for testing purposes
};
    
// returns [1, 3, 2]
console.log(array_move([1, 2, 3], -1, -2));

Что должно правильно учитывать такие вещи, как array_move([1, 2, 3], -1, -2) (переместите последний элемент со второго на последнее место).Результат для этого должен быть [1, 3, 2].

В любом случае, в исходном вопросе вы бы сделали array_move(arr, 0, 2) для a после c.Для d до b вы должны сделать array_move(arr, 3, 1).

239 голосов
/ 24 августа 2011

Вот один вкладыш, который я нашел на JSPerf ....

Array.prototype.move = function(from, to) {
    this.splice(to, 0, this.splice(from, 1)[0]);
};

, который приятно читать, но если вам нужна производительность (в небольших наборах данных), попробуйте ...

 Array.prototype.move2 = function(pos1, pos2) {
    // local variables
    var i, tmp;
    // cast input parameters to integers
    pos1 = parseInt(pos1, 10);
    pos2 = parseInt(pos2, 10);
    // if positions are different and inside array
    if (pos1 !== pos2 && 0 <= pos1 && pos1 <= this.length && 0 <= pos2 && pos2 <= this.length) {
      // save element from position 1
      tmp = this[pos1];
      // move element down and shift other elements up
      if (pos1 < pos2) {
        for (i = pos1; i < pos2; i++) {
          this[i] = this[i + 1];
        }
      }
      // move element up and shift other elements down
      else {
        for (i = pos1; i > pos2; i--) {
          this[i] = this[i - 1];
        }
      }
      // put element from position 1 to destination
      this[pos2] = tmp;
    }
  }

Я не могу взять кредит, все это должно пойти на Ричард Скарротт .В этом тесте производительности он превосходит метод на основе сплайсинга для небольших наборов данных.Однако это значительно медленнее на больших наборах данных , как отмечает Дарвейн .

156 голосов
/ 24 июня 2011

Мне нравится этот способ. Это работает, это сжато и изящно.

function arraymove(arr, fromIndex, toIndex) {
    var element = arr[fromIndex];
    arr.splice(fromIndex, 1);
    arr.splice(toIndex, 0, element);
}

Примечание: всегда не забывайте проверять границы вашего массива.

Вот jsFiddle для проверки: https://jsfiddle.net/aq9Laaew/286055/

31 голосов
/ 01 августа 2013

Метод splice () добавляет / удаляет элементы в / из массива и возвращает удаленные элементы.

Примечание. Этот метод изменяет исходный массив. / W3schools /

Array.prototype.move = function(from,to){
  this.splice(to,0,this.splice(from,1)[0]);
  return this;
};

var arr = [ 'a', 'b', 'c', 'd', 'e'];
arr.move(3,1);//["a", "d", "b", "c", "e"]


var arr = [ 'a', 'b', 'c', 'd', 'e'];
arr.move(0,2);//["b", "c", "a", "d", "e"]

как функция цепная это тоже работает:

alert(arr.move(0,2).join(','));

демо здесь

24 голосов
/ 12 января 2014

Мой 2с. Легко читается, работает, работает быстро, не создает новых массивов.

function move(array, from, to) {
  if( to === from ) return array;

  var target = array[from];                         
  var increment = to < from ? -1 : 1;

  for(var k = from; k != to; k += increment){
    array[k] = array[k + increment];
  }
  array[to] = target;
  return array;
}
16 голосов
/ 15 марта 2011

Получил эту идею от @Reid, когда что-то помещалось на место элемента, который должен быть перемещен, чтобы сохранить размер массива постоянным.Это упрощает расчеты.Кроме того, добавление пустого объекта имеет дополнительные преимущества, заключающиеся в возможности уникального поиска в дальнейшем.Это работает, потому что два объекта не равны, пока они не ссылаются на один и тот же объект.

({}) == ({}); // false

Итак, вот функция, которая принимает исходный массив и исходные, целевые индексы.При необходимости вы можете добавить его в Array.prototype.

function moveObjectAtIndex(array, sourceIndex, destIndex) {
    var placeholder = {};
    // remove the object from its initial position and
    // plant the placeholder object in its place to
    // keep the array length constant
    var objectToMove = array.splice(sourceIndex, 1, placeholder)[0];
    // place the object in the desired position
    array.splice(destIndex, 0, objectToMove);
    // take out the temporary object
    array.splice(array.indexOf(placeholder), 1);
}
15 голосов
/ 24 сентября 2015

Это основано на решении @ Reid. За исключением:

  • Я не изменяю прототип Array.
  • Перемещение элемента за пределы вправо не создает undefined элементов, оно просто перемещает элемент в крайнее правое положение.

Функция:

function move(array, oldIndex, newIndex) {
    if (newIndex >= array.length) {
        newIndex = array.length - 1;
    }
    array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]);
    return array;
}

Юнит-тесты:

describe('ArrayHelper', function () {
    it('Move right', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 0, 1);
        assert.equal(array[0], 2);
        assert.equal(array[1], 1);
        assert.equal(array[2], 3);
    })
    it('Move left', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 1, 0);
        assert.equal(array[0], 2);
        assert.equal(array[1], 1);
        assert.equal(array[2], 3);
    });
    it('Move out of bounds to the left', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 1, -2);
        assert.equal(array[0], 2);
        assert.equal(array[1], 1);
        assert.equal(array[2], 3);
    });
    it('Move out of bounds to the right', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 1, 4);
        assert.equal(array[0], 1);
        assert.equal(array[1], 3);
        assert.equal(array[2], 2);
    });
});
8 голосов
/ 17 апреля 2018

Вот мое решение для одной линии ES6 с необязательным параметром on.

if (typeof Array.prototype.move === "undefined") {
  Array.prototype.move = function(from, to, on = 1) {
    this.splice(to, 0, ...this.splice(from, on))
  }
}

Адаптация первого решения, предложенного digiguru

Параметр on - это номер элемента, начиная с from, который вы хотите переместить.

7 голосов
/ 15 марта 2011

Один из подходов заключается в создании нового массива с кусочками в нужном вам порядке, используя метод среза.

Пример

var arr = [ 'a', 'b', 'c', 'd', 'e'];
var arr2 = arr.slice(0,1).concat( ['d'] ).concat( arr.slice(2,4) ).concat( arr.slice(4) );
  • arr.slice (0, 1) дает вам ['a']
  • arr.slice (2,4) дает вам ['b', 'c']
  • arr.slice (4) дает вам ['e']
6 голосов
/ 15 марта 2011

Может помочь splice метод Array: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice

Просто имейте в виду, что он может быть относительно дорогим, поскольку он должен активно переиндексировать массив.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...