development

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

big-blog 2020. 2. 17. 22:18
반응형

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


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

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. 그런 다음 splicenew_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은 다음과 같습니다. https://jsfiddle.net/aq9Laaew/286055/


접합부 () 메소드는 추가 / 어레이 /로부터 항목을 제거하고, 복귀 제거 항목 (들).

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

선택적 매개 변수 가있는 내 라이너 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

매개 변수 onfrom이동하려는 요소의 수입니다 .


슬라이스 방법을 사용하여 원하는 순서대로 조각으로 새 배열을 만드는 방법이 있습니다.

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']를줍니다

도움 spliceArray될 수 있는 방법 : https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice

어레이를 적극적으로 재 인덱싱해야하므로 상대적으로 비쌀 수 있습니다.


기본 미적분을 구현하고 배열 요소를 한 위치에서 다른 위치로 이동하기위한 범용 함수를 만들 수 있습니다.

JavaScript의 경우 다음과 같습니다.

function magicFunction (targetArray, indexFrom, indexTo) { 

    targetElement = targetArray[indexFrom]; 
    magicIncrement = (indexTo - indexFrom) / Math.abs (indexTo - indexFrom); 

    for (Element = indexFrom; Element != indexTo; Element += magicIncrement){ 
        targetArray[Element] = targetArray[Element + magicIncrement]; 
    } 

    targetArray[indexTo] = targetElement; 

}

자세한 설명은 "gloommatter"에서 "배열 요소 이동"을 확인하십시오.

http://www.gloommatter.com/DDesign/programming/moving-any-array-elements-universal-function.html


불변의 이동 방법 (원래 배열을 변경하지 않은 방법)이 필요했기 때문에 @Reid의 허용 된 대답을 간단하게 Object.assign을 사용하여 배열의 복사본을 만들어 스플 라이스를 만들기 전에 적용했습니다.

Array.prototype.immutableMove = function (old_index, new_index) {
  var copy = Object.assign([], this);
  if (new_index >= copy.length) {
      var k = new_index - copy.length;
      while ((k--) + 1) {
          copy.push(undefined);
      }
  }
  copy.splice(new_index, 0, copy.splice(old_index, 1)[0]);
  return copy;
};

여기에 작동중인 jsfiddle이 있습니다 .


    Array.prototype.moveUp = function (value, by) {
        var index = this.indexOf(value),
            newPos = index - (by || 1);

        if (index === -1)
            throw new Error("Element not found in array");

        if (newPos < 0)
            newPos = 0;

        this.splice(index, 1);
        this.splice(newPos, 0, value);
    };

    Array.prototype.moveDown = function (value, by) {
        var index = this.indexOf(value),
            newPos = index + (by || 1);

        if (index === -1)
            throw new Error("Element not found in array");

        if (newPos >= this.length)
            newPos = this.length;

        this.splice(index, 1);
        this.splice(newPos, 0, value);
    };



    var arr = ['banana', 'curyWurst', 'pc', 'remembaHaruMembaru'];

    alert('withiout changes= '+arr[0]+' ||| '+arr[1]+' ||| '+arr[2]+' ||| '+arr[3]);
    arr.moveDown(arr[2]);


    alert('third word moved down= '+arr[0] + ' ||| ' + arr[1] + ' ||| ' + arr[2] + ' ||| ' + arr[3]);
    arr.moveUp(arr[2]);
    alert('third word moved up= '+arr[0] + ' ||| ' + arr[1] + ' ||| ' + arr[2] + ' ||| ' + arr[3]);

http://plnkr.co/edit/JaiAaO7FQcdPGPY6G337?p=preview


여기에 대한 답변을 ECMAScript 6기반 으로 불변의 솔루션을 구현했습니다 @Merc.

const moveItemInArrayFromIndexToIndex = (array, fromIndex, toIndex) => {
  if (fromIndex === toIndex) return array;

  const newArray = [...array];

  const target = newArray[fromIndex];
  const inc = toIndex < fromIndex ? -1 : 1;

  for (let i = fromIndex; i !== toIndex; i += inc) {
    newArray[i] = newArray[i + inc];
  }

  newArray[toIndex] = target;

  return newArray;
};

변수 이름은 짧아 질 수 있으며, 긴 이름을 사용하여 코드 자체를 설명 할 수 있습니다.


Array.move.js

요약

배열 내에서 요소를 이동하여 이동 된 요소가 포함 된 배열을 반환합니다.

통사론

array.move(index, howMany, toIndex);

매개 변수

index : 요소를 이동할 인덱스. 음수이면 색인 이 끝에서 시작됩니다.

howMany : 인덱스 에서 이동할 요소 수 .

toIndex : 이동 한 요소를 배치 할 배열의 인덱스입니다. 음수이면 toIndex 가 끝에서 시작됩니다.

용법

array = ["a", "b", "c", "d", "e", "f", "g"];

array.move(3, 2, 1); // returns ["d","e"]

array; // returns ["a", "d", "e", "b", "c", "f", "g"]

폴리 필

Array.prototype.move || Object.defineProperty(Array.prototype, "move", {
    value: function (index, howMany, toIndex) {
        var
        array = this,
        index = parseInt(index) || 0,
        index = index < 0 ? array.length + index : index,
        toIndex = parseInt(toIndex) || 0,
        toIndex = toIndex < 0 ? array.length + toIndex : toIndex,
        toIndex = toIndex <= index ? toIndex : toIndex <= index + howMany ? index : toIndex - howMany,
        moved;

        array.splice.apply(array, [toIndex, 0].concat(moved = array.splice(index, howMany)));

        return moved;
    }
});

작고 먼 거리를 이동할 때 두 가지를 결합하여 조금 더 잘 작동했습니다. 나는 상당히 일관된 결과를 얻지 만, 아마도 다른 사람과는 다른 크기로 다르게 작동하도록 똑똑한 사람이 약간 조정할 수 있습니다.

거리를 좁힐 때 다른 방법을 사용하면 스플 라이스를 사용하는 것보다 훨씬 빠릅니다 (x10). 배열 길이에 따라 변경 될 수 있지만 큰 배열의 경우에는 해당됩니다.

function ArrayMove(array, from, to) {
    if ( Math.abs(from - to) > 60) {
        array.splice(to, 0, array.splice(from, 1)[0]);
    } else {
        // works better when we are not moving things very far
        var target = array[from];
        var inc = (to - from) / Math.abs(to - from);
        var current = from;
        for (; current != to; current += inc) {
            array[current] = array[current + inc];
        }
        array[to] = target;    
    }
}

http://jsperf.com/arraymove-many-sizes


이 버전은 모든 목적에 이상적이지는 않으며 모든 사람이 쉼표 표현식을 좋아하지는 않지만 순수한 표현을 가진 새로운 라이너를 만들어 새로운 사본을 만듭니다.

const move = (from, to, ...a) => (a.splice(to, 0, ...a.splice(from, 1)), a)

약간의 성능 향상 버전은 이동이 필요하지 않은 경우 입력 배열을 반환하며, 배열이 변경되지 않으므로 여전히 불변의 사용이 가능하며 순수한 표현입니다.

const move = (from, to, ...a) => 
    from === to 
    ? a 
    : (a.splice(to, 0, ...a.splice(from, 1)), a)

둘 중 하나의 호출은

const shuffled = move(fromIndex, toIndex, ...list)

즉, 새로운 사본을 생성하기 위해 확산에 의존합니다. 고정 된 arity 3 move을 사용하면 단일 표현식 속성이나 비파괴적인 특성 또는의 성능 이점이 위태로워집니다 splice. 다시 말하지만, 프로덕션 사용에 대한 제안보다 몇 가지 기준을 충족시키는 예가 더 많습니다.


나는 @Reid 의 좋은 대답을 사용 했지만 배열의 끝에서 한 단계 더 나아가 요소를 루프 에서와 같이 처음으로 이동하는 데 어려움을 겪었습니다 . 예를 들어 [ 'a', 'b', 'c']는 .move (2,3)를 호출하여 [ 'c', 'a', 'b']가되어야합니다.

new_index> = this.length의 경우를 변경하여이를 달성했습니다.

Array.prototype.move = function (old_index, new_index) {
        console.log(old_index + " " + new_index);
        while (old_index < 0) {
            old_index += this.length;
        }
        while (new_index < 0) {
            new_index += this.length;
        }
        if (new_index >= this.length) {
            new_index = new_index % this.length;
        }
        this.splice(new_index, 0, this.splice(old_index, 1)[0]);
        return this; // for testing purposes
    };

Array 프로토 타입을 가지고 노는 것은 많은 장소에서 ( Array.prototype에 커스텀 함수 추가 ) 언급되어 있습니다. 어쨌든 다양한 게시물에서 최고를 결합했습니다. 나는 현대 Javascript를 사용하여 이것을 제공했습니다.

    Object.defineProperty(Array.prototype, 'immutableMove', {
        enumerable: false,
        value: function (old_index, new_index) {
            var copy = Object.assign([], this)
            if (new_index >= copy.length) {
                var k = new_index - copy.length;
                while ((k--) + 1) { copy.push(undefined); }
            }
            copy.splice(new_index, 0, copy.splice(old_index, 1)[0]);
            return copy
        }
    });

    //how to use it
    myArray=[0, 1, 2, 3, 4];
    myArray=myArray.immutableMove(2, 4);
    console.log(myArray);
    //result: 0, 1, 3, 4, 2

희망은 누구에게나 유용 할 수 있습니다


Reid의 훌륭한 답변에 덧붙여서 (그리고 내가 말할 수 없기 때문에); 모듈러스를 사용하여 음수 지수와 너무 큰 지수를 "롤오버"할 수 있습니다.

function array_move(arr, old_index, new_index) {
  new_index =((new_index % arr.length) + arr.length) % arr.length;
  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)); 


let ar = ['a', 'b', 'c', 'd'];

function change( old_array, old_index , new_index ){

  return old_array.map(( item , index, array )=>{
    if( index === old_index ) return array[ new_index ];
    else if( index === new_index ) return array[ old_index ];
    else return item;
  });

}

let result = change( ar, 0, 1 );

console.log( result );

결과:

["b", "a", "c", "d"]

const move = (from, to, ...a) =>from === to ? a : (a.splice(to, 0, ...a.splice(from, 1)), a);
const moved = move(0, 2, ...['a', 'b', 'c']);
console.log(moved)

참고 URL : https://stackoverflow.com/questions/5306680/move-an-array-element-from-one-array-position-to-another



도와주세요.
반응형