[javascript] 한 배열 위치에서 다른 배열 위치로 배열 요소 이동

배열 요소를 이동하는 방법을 알아내는 데 어려움을 겪고 있습니다. 예를 들면 다음과 같습니다.

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] = ‘이자형’

이것은 매우 간단해야하지만 머리를 감쌀 수는 없습니다.



답변

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)위한 ac. 들어 d전에 b, 당신이 할 것입니다 array_move(arr, 3, 1).


답변

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

크레딧을받을 수 없습니다 . 모두 Richard Scarrott 로 가야합니다 . 이 성능 테스트 에서 더 작은 데이터 세트에 대한 스플 라이스 기반 방법을 능가합니다 . 그러나 Darwayne이 지적한 것처럼 더 큰 데이터 세트 에서는 속도가 상당히 느립니다 .


답변

나는이 방법을 좋아한다. 간결하고 작동합니다.

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

참고 : 항상 배열 범위를 확인하십시오.

jsFiddle에서 스 니펫 실행


답변

접합부 () 메소드는 추가 / 배열로부터 /로 항목 및 복귀 제거 제거를 항목 (들).

참고 :이 방법은 원래 배열을 변경합니다. / 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(','));

여기 데모


답변

내 2c. 읽기 쉽고 작동하며 빠르며 새 배열을 만들지 않습니다.

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


답변

배열 크기를 일정하게 유지하기 위해 이동 해야하는 항목 대신 무언가를 밀어 넣는 @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);
}


답변

이것은 @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);
    });
});