자바 스크립트 스왑 배열 요소


228

배열에서 두 요소를 바꾸는 더 간단한 방법이 있습니까?

var a = list[x], b = list[y];
list[y] = a;
list[x] = b;

답변:


411

임시 변수는 하나만 필요합니다.

var b = list[y];
list[y] = list[x];
list[x] = b;

10 년 후 벨트에서 많은 ES6 채택을 통해 도용 최고 답변을 수정합니다 .

array가 주어지면 다음 arr = [1,2,3,4]과 같이 한 줄로 값을 바꿀 수 있습니다.

[arr[0], arr[1]] = [arr[1], arr[0]];

이것은 배열을 생성합니다 [2,1,3,4]. 이것은 할당을 파괴하고 있습니다.


2
심지어 ECMAScript를 6 Destructuring 할당을 사용하지 않고, 실제로는 임시 변수와 현재의 범위를 오염없이 동시 스왑을 얻을 수 있습니다 a = [b, b = a][0];@Jan에 의해 지적 아웃로가 교차 언어 (예 : C / C의 나는 여전히 자신이 임시 변수 접근 방식을 활용 찾을 수 있지만 ++ ) 및 일반적으로 내 마음에 나타나는 첫 번째 방법.
Ultimater

3
다른 사람들이 아래에 표시된 것처럼 es6으로 교체 (돌연변이) 할 수 있습니다.[ list[y], list[x] ] = [ list[x], list[y] ];
protoEvangelion

[arr[0], arr[1]] = [arr[1], arr[0]]단지 생산 [2, 1]배열의 나머지 부분없이
Yerko 팔마

8
@YerkoPalma - 발현 복귀 [2,1] 그러나 일본어 배열로 변이한다 [2,1,3,4]는
danbars

111

기본 자바 스크립트를 사용하여 단일 표현식을 원하는 경우 스플 라이스 연산의 반환 값에 제거 된 요소가 포함되어 있음을 기억하십시오.

var A = [1, 2, 3, 4, 5, 6, 7, 8, 9], x= 0, y= 1;
A[x] = A.splice(y, 1, A[x])[0];
alert(A); // alerts "2,1,3,4,5,6,7,8,9"

편집하다:

[0]같은 식의 끝 부분에 필요한 Array.splice()반환 배열,이 상황에서 우리는 반환 된 배열의 단일 요소를 필요로한다.


3
splice는 배열을 반환합니다. 예를 들어, 스왑 작업 후 배열은 실제로 다음과 같습니다. [[2], 1, 3, 4, 5, 6, 7, 8, 9]
JPot

1
A [x] = A. 스플 라이스 (y, 1, A [x]) [0]; ? mootools에서 Array.implement ({swap : function (x, y) {this [y] = this.splice (x, 1, this [y]) [0];}});
ken

확인 된 [0]이 없습니다.
Johann Philipp Strathausen

훌륭하고 짧지 만 @aelgoa가 말했듯이, 거의 느리고 간단한 스왑
ofir_aghai

75

이것은 괜찮아 보인다 ....

var b = list[y];
list[y] = list[x];
list[x] = b;

Howerver 사용

var b = list[y];

b 변수가 나머지 범위에 대해 존재 함을 의미합니다. 이로 인해 메모리 누수가 발생할 수 있습니다. 가능하지는 않지만 피하는 것이 좋습니다.

이것을 Array.prototype.swap에 넣는 것이 좋습니다.

Array.prototype.swap = function (x,y) {
  var b = this[x];
  this[x] = this[y];
  this[y] = b;
  return this;
}

다음과 같이 호출 할 수 있습니다.

list.swap( x, y )

이것은 메모리 누수DRY를 피하는 깔끔한 접근 방법 입니다.


나도 이것을 좋아한다. Array.implement ({swap : function (x, y) {x = this [x]; this [x] = this [y]; this [y] = x; 이것을 반환;}});
ken

1
이거 좋은데. 어쩌면 일부 경계 확인? Array.prototype.swap = function (x,y) { if (x >= 0 && x < this.length && y >= 0 && y < this.length) { var b = this[x]; this[x] = this[y]; this[y] = b; } return this; };
David R.

@DavidR. 바운드 검사는 불필요하고 불필요합니다. 호출자는 원하는 경우 그러한 검사를 수행하는 데 필요한 모든 것을 갖추고 있지만 대부분의 경우 이미 어떤 종류의 루프에 있기 때문에 x와 y가 경계에 있다는 것을 알고 있습니다.
Neil

6
함수에 래핑하여 "잠재적 메모리 누수"를 피할 수 없습니까?
Carcigenicate

3
잠재적 인 "평평한"사고를 피하기 위해 내장 유형의 프로토 타입 체인을 건드리지 않았습니다.
AaronDancer

54

에 따르면 Metafilter에 어떤 임의의 사람 , "자바 스크립트의 최신 버전은 훨씬 더 깔끔하게 (다른 것들 사이) 교환을 할 수 있도록"

[ list[x], list[y] ] = [ list[y], list[x] ];

빠른 테스트에서이 Python 코드 는 현재 "Google Apps Script"( ". gs")에서 사용되는 JavaScript 버전에서 훌륭하게 작동합니다. 아아, 추가 테스트에 따르면이 코드는 "Uncaught ReferenceError : Assignment in invalid left-side side in assignment"를 보여줍니다. 모든 버전의 JavaScript ( ". js")에서 Chrome 버전 24.0.1312.57 m이 사용됩니다.


2
이것은 ES6 제안의 일부입니다 : 아직 공식화되지 않았으므로 모든 곳에서 작동한다고 절대 가정해서는 안됩니다 (그렇다면 훌륭 할 것입니다 ...).
Isiah Meadows

2
최신 Firefox 버전 (39.0.3)에서 작동합니다.
Jamie

2
Chrome 버전 54.0.2840.71 및 이전 버전에서 작동합니다. 또한 babel 과 같은 ES6 트랜스 필러를 사용하는 경우이 코드를 가져와야 합니다.
amoebe

3
이 솔루션을 좋아하십시오. 의도 한대로 청소하십시오. 9 년 전에 질문이 너무 나빴습니다 ...
DavidsKanal

2
es6에서 표준화되었으며이 기능을 파괴라고합니다.
AL-zami

29

음, 값을 모두 버퍼링 할 필요는 없습니다 . 하나만 :

var tmp = list[x];
list[x] = list[y];
list[y] = tmp;

13
'B'다음 사용하는 'TMP'소리를보다 합리적인
mtasic85

@ofir_aghai 예, 당신 말이 맞습니다 : 10+ 년 전, 다른 답변이 22 초 전에 게시되었습니다 (12 : 14 : 16Z vs 12 : 14 : 38Z) ...
Marc Gravell

규칙적인 날에 나는 그것을 고수했다. 그러나 초 발행 및 당신의 10 년 존중 ;-) 여기에 다시 시작해서
ofir_aghai

죄송합니다. 투표를 변경할 수 없습니다 .. "이 답변을 편집하지 않으면 투표가 잠기 게됩니다"
ofir_aghai

22

다음과 같은 방법으로 배열의 요소를 교체 할 수 있습니다.

list[x] = [list[y],list[y]=list[x]][0]

다음 예를 참조하십시오.

list = [1,2,3,4,5]
list[1] = [list[3],list[3]=list[1]][0]
//list is now [1,4,3,2,5]

참고 : 일반 변수와 동일한 방식으로 작동합니다.

var a=1,b=5;
a = [b,b=a][0]

6
이것은 ES6 (다음 JavaScript 버전)에서 이것을 수행하는 표준 올바른 방법과 놀랍게 유사합니다 [list[x], list[y]] = [list[y], list[x]];.
Isiah Meadows

1
이것은 구조 해제를 통해 ES6 어레이 스왑과 관련이 없습니다. 이것은 JS 워크 플로를 영리하게 사용하는 것입니다. 인라인 코딩을 자주 사용하는 경우 아름다운 스왑 패턴this[0] > this[1] && (this[0] = [this[1],this[1]=this[0]][0]);
Redu

18

숫자 값을 사용하면 비트 xor를 사용하여 임시 변수를 피할 수 있습니다

list[x] = list[x] ^ list[y];
list[y] = list[y] ^ list[x];
list[x] = list[x] ^ list[y];

또는 산술 합계 (x + y가 데이터 유형의 최대 값보다 작은 경우에만 작동 함)

list[x] = list[x] + list[y];
list[y] = list[x] - list[y];
list[x] = list[x] - list[y];

2
vader에서와 같이 다스입니까? +1
krosenvold

7
뭔가 잘못되었다. 에 list[y] = list[x] - list[x];동일 하지 list[y] = 0;않습니까?
ErikE

3
xor 트릭은 x = y 일 때도 실패합니다. list [x]를 원래 값으로 유지할 것으로 예상 할 때 list [x]를 0으로 설정합니다.
David Cary

1
기술적으로 임시 값을 만들면 배열의 관련 영역 밖으로 이동하지 않습니다.
Mark Smit

1
더 단순하거나 더 효율적이거나 일반적인 것도 아닙니다.
LoganMzz

17

질문이있을 때 존재하지 않았지만 ES2015는 배열 파괴를 도입하여 다음과 같이 작성할 수 있습니다.

let a = 1, b = 2;
// a: 1, b: 2
[a, b] = [b, a];
// a: 2, b: 1

14
배열 내부에서 이와 같이 바꾸려면 :[list[x], list[y]] = [list[y], list[x]];
Stromata

15

배열의 두 연속 요소를 바꾸려면

array.splice(IndexToSwap,2,array[IndexToSwap+1],array[IndexToSwap]);

13

http://www.greywyvern.com/?post=265 에서 다이제스트

var a = 5, b = 9;    
b = (a += b -= a) - b;    
alert([a, b]); // alerts "9, 5"

1
이것을 swap(a, b)함수로 감싸면 가독성에 대해 걱정할 필요가 없습니다.
AccidentalTaylorExpansion

1
정수에만 작동
Redu

이것은 아마도 제대로 최적화되지 않습니다. 컴파일러는이를 "스왑 관용구"로 감지 할 수 있지만 두 유형이 모두 int이고 별칭 이 아닌지 확실하지 않으면 효과를 확신 할 수 없습니다 .
mwfearnley


9

세 번째 변수를 정의 할 필요없이 이러한 솔루션을 고려하십시오.

function swap(arr, from, to) {
  arr.splice(from, 1, arr.splice(to, 1, arr[from])[0]);
}

var letters = ["a", "b", "c", "d", "e", "f"];

swap(letters, 1, 4);

console.log(letters); // ["a", "e", "c", "d", "b", "f"]

참고 : 배열 길이와 같은 추가 검사를 추가 할 수 있습니다. 이 솔루션은 변경 가능 하므로 swap함수는 새로운 배열을 반환 할 필요가 없으며 전달 된 배열에 대한 돌연변이 만 수행합니다.


부가으로 확산 연산자도 사용할 수있다 :arr.splice(from, 1, arr.splice(to, 1, ...arr[from]))
Orkun Tuzel

7

다음과 같은 간단한 ID 함수를 사용하여 여러 유형의 객체 또는 리터럴을 다양한 유형으로 바꿀 수 있습니다.

var swap = function (x){return x};
b = swap(a, a=b);
c = swap(a, a=b, b=c);

문제의 경우 :

var swap = function (x){return x};
list[y]  = swap(list[x], list[x]=list[y]);

추가 인수가 선언되거나 사용되지 않더라도 추가 인수를 허용하므로 JavaScript에서 작동합니다. 할당 a=b후 등 a은 함수에 전달됩니다.


Hackish ...하지만 함수를 한 번만 사용하는 경우 더 잘 할 수 list[y] = (function(x){return x})(list[x],list[x]=list[y]);있습니다. 또는 ES6 (다음 버전의 JS)에 관심이 있다면 매우 쉽습니다 [list[x], list[y]] = [list[y], list[x].. 다음 버전의 JavaScript에 더 많은 기능 및 클래스 기반 측면을 추가하게되어 기쁩니다.
Isiah Meadows

6

둘 이상의 요소 (고정 번호)

[list[y], list[x]] = [list[x], list[y]];

임시 변수가 필요하지 않습니다!

나는 단순히 전화하는 것에 대해 생각하고 있었다 list.reverse().
하지만 그때는 스왑으로 만 작동한다는 것을 깨달았습니다.list.length = x + y + 1 .

가변 개수의 요소

Mapmap을 포함 하여이 효과에 대한 다양한 현대 Javascript 구성을 살펴 보았지만 슬프게도이 구식 루프 기반 구성보다 더 컴팩트하거나 빠른 코드는 없었습니다.

function multiswap(arr,i0,i1) {/* argument immutable if string */
    if (arr.split) return multiswap(arr.split(""), i0, i1).join("");
    var diff = [];
    for (let i in i0) diff[i0[i]] = arr[i1[i]];
    return Object.assign(arr,diff);
}

Example:
    var alphabet = "abcdefghijklmnopqrstuvwxyz";
    var [x,y,z] = [14,6,15];
    var output = document.getElementsByTagName("code");
    output[0].innerHTML = alphabet;
    output[1].innerHTML = multiswap(alphabet, [0,25], [25,0]);
    output[2].innerHTML = multiswap(alphabet, [0,25,z,1,y,x], [25,0,x,y,z,3]);
<table>
    <tr><td>Input:</td>                        <td><code></code></td></tr>
    <tr><td>Swap two elements:</td>            <td><code></code></td></tr>
    <tr><td>Swap multiple elements:&nbsp;</td> <td><code></code></td></tr>
</table>


5

흥미로운 스왑 방법이 있습니다.

var a = 1;
var b = 2;
[a,b] = [b,a];

(ES6 방식)


5
배열의 경우 더var a= [7,8,9,10], i=2, j=3;[a[i],a[j]] = [a[j],a[i]];
caub

4
var a = [1,2,3,4,5], b=a.length;

for (var i=0; i<b; i++) {
    a.unshift(a.splice(1+i,1).shift());
}
a.shift();
//a = [5,4,3,2,1];

3

다음은 변이하지 않는 하나의 라이너입니다 list.

let newList = Object.assign([], list, {[x]: list[y], [y]: list[x]})

(질문이 게시 된 2009 년에는 사용할 수없는 언어 기능을 사용합니다!)


1

다음은 arr의 i2와 i1의 값을 교환하는 컴팩트 버전입니다.

arr.slice(0,i1).concat(arr[i2],arr.slice(i1+1,i2),arr[i1],arr.slice(i2+1))

임시 변수 방법보다 효율성이 떨어집니다. 세 번 슬라이스되고 세 개의 슬라이스 배열 사이에 두 개의 객체와 함께 연결된 수정 된 배열을 효과적으로 반환합니다. 어레이에 단순히 할당하기 위해 필요한 값을 얻는 데 필요한 것보다 메모리가 두 배 이상 필요합니다 (아무 것도 수행되지 않았습니다).
Isiah Meadows

1

다음은 인덱스가 배열에 존재하는지 먼저 확인하는 변형입니다.

Array.prototype.swapItems = function(a, b){
    if(  !(a in this) || !(b in this) )
        return this;
    this[a] = this.splice(b, 1, this[a])[0];
    return this;
}

this색인이 존재하지 않으면 현재 반환 되지만 실패시 동작을 쉽게 수정할 수 있습니다.


1

임시 변수 또는 ES6 스왑 방법없이 배열에서 첫 번째 요소와 마지막 요소를 교체합니다 [a, b] = [b, a]

[a.pop(), ...a.slice(1), a.shift()]


1

기존 배열을 변경하지 않고 배열을 복제하는 Typescript 솔루션

export function swapItemsInArray<T>(items: T[], indexA: number, indexB: number): T[] {
  const itemA = items[indexA];

  const clone = [...items];

  clone[indexA] = clone[indexB];
  clone[indexB] = itemA;

  return clone;
}

0

재미를 위해서 추가 변수를 사용하지 않는 다른 방법은 다음과 같습니다.

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

// swap index 0 and 2
arr[arr.length] = arr[0];   // copy idx1 to the end of the array
arr[0] = arr[2];            // copy idx2 to idx1
arr[2] = arr[arr.length-1]; // copy idx1 to idx2
arr.length--;               // remove idx1 (was added to the end of the array)


console.log( arr ); // -> [3, 2, 1, 4, 5, 6, 7, 8, 9]


0

간결성을 위해 여기에 위의 모든 concat 및 슬라이싱보다 약간 덜 추한 추한 1 라이너 버전이 있습니다. 받아 들여지는 대답은 진정으로 가고 더 읽기 쉬운 방법입니다.

주어진:

var foo = [ 0, 1, 2, 3, 4, 5, 6 ];

두 지수 (a와 b)의 값을 바꾸려면; 그런 다음이 작업을 수행합니다.

foo.splice( a, 1, foo.splice(b,1,foo[a])[0] );

예를 들어 3과 5를 바꾸려면 다음과 같이하십시오.

foo.splice( 3, 1, foo.splice(5,1,foo[3])[0] );

또는

foo.splice( 5, 1, foo.splice(3,1,foo[5])[0] );

둘 다 동일한 결과를 산출합니다.

console.log( foo );
// => [ 0, 1, 2, 5, 4, 3, 6 ]

#splicehatersarepunks :)


0

ES5에서 temp 변수를 사용하지 않으려면 배열 요소를 바꾸는 방법 중 하나입니다.

var swapArrayElements = function (a, x, y) {
  if (a.length === 1) return a;
  a.splice(y, 1, a.splice(x, 1, a[y])[0]);
  return a;
};

swapArrayElements([1, 2, 3, 4, 5], 1, 3); //=> [ 1, 4, 3, 2, 5 ]

이렇게하면 임시 변수를 만드는 대신 a.splice제거 된 요소가있는 배열을 반환하는 두 개의 새 배열을 만듭니다 . developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
XCS

더 잘할 수있는 방법이 있습니까? @Cristy
venkat7668

허용되는 답변은 간단합니다. 변수 선언 수에 제한이있는 경우 (대개 인터뷰 목적 :) 유용합니다. 그러나 언급 한 것처럼 메모리 효율적이지 않습니다. @Cristy
venkat7668

나는 개인적으로 그것이 나쁜 습관이라고 생각하며 초보자에게 권장해서는 안됩니다. 또한 읽기가 매우 어렵습니다.
XCS

0

이 기능을 사용해보십시오 ...

$(document).ready(function () {
        var pair = [];
        var destinationarray = ['AAA','BBB','CCC'];

        var cityItems = getCityList(destinationarray);
        for (var i = 0; i < cityItems.length; i++) {
            pair = [];
            var ending_point = "";
            for (var j = 0; j < cityItems[i].length; j++) {
                pair.push(cityItems[i][j]);
            }
            alert(pair);
            console.log(pair)
        }

    });
    function getCityList(inputArray) {
        var Util = function () {
        };

        Util.getPermuts = function (array, start, output) {
            if (start >= array.length) {
                var arr = array.slice(0);
                output.push(arr);
            } else {
                var i;

                for (i = start; i < array.length; ++i) {
                    Util.swap(array, start, i);
                    Util.getPermuts(array, start + 1, output);
                    Util.swap(array, start, i);
                }
            }
        }

        Util.getAllPossiblePermuts = function (array, output) {
            Util.getPermuts(array, 0, output);
        }

        Util.swap = function (array, from, to) {
            var tmp = array[from];
            array[from] = array[to];
            array[to] = tmp;
        }
        var output = [];
        Util.getAllPossiblePermuts(inputArray, output);
        return output;
    }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


0

var arr = [1, 2];
arr.splice(0, 2, arr[1], arr[0]);
console.log(arr); //[2, 1]


1
이 코드 스 니펫은 문제를 해결할 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 실제로 도움이됩니다. 앞으로 독자에게 질문에 대한 답변을 제공하고 있으며 해당 사람들이 코드 제안의 이유를 모를 수도 있습니다.
Alessio

-1

ES6 을 사용하면 다음과 같이 할 수 있습니다 ...

두 배열 이 있다고 상상해보십시오 ...

const a = ["a", "b", "c", "d", "e"];
const b = [5, 4, 3, 2, 1];

첫 번째 값을 바꾸고 싶습니다.

const [a0] = a;
a[0] = b[0];
b[0] = a0;

그리고 가치 :

a; //[5, "b", "c", "d", "e"]
b; //["a", 4, 3, 2, 1]

-2
Array.prototype.swap = function(a, b) {
  var temp = this[a];
  this[a] = this[b];
  this[b] = temp;
};

용법:

var myArray = [0,1,2,3,4...];
myArray.swap(4,1);

1
무례 할 필요는 없습니다. 또한 Array프로토 타입을 확장하는 것은 요청한 것의 일부가 아니 었 습니다. 프로토 타입을 확장하는 것이 좋은 것보다 더 혼란 스러울 수 있습니다.
Mathias Lykkegaard Lorenzen

어떻게 답변의 일부가 미쳤다고 표현하고 배열 프로토 타입을 확장하는 것이 좋을 것이고, 리턴을 추가하면 체인을 만들 수있게 될 것입니다.
user2472643

2
"올바른 방법"으로 표현하고 있습니다. 잘못된 인상을 줄 수 있습니다. 대신, 당신이하고있는 것 (시제품 연장)과 방금 설명한대로 그것이 유용한 방법을 언급하는 것이 좋습니다.
Mathias Lykkegaard Lorenzen

1
gotcha, 죄송하지만 내 poise는 때때로 쌍에 있지 않습니다 ^ _ ^
user2472643

2
당신은 답변의 맥락에서 문제를 설명하는 유일한 사람입니다 ... 먼저 부정적인 점수는 작동하지 않는 답변을 위해 예약되어야합니다. 둘째, 이것은 충돌을 일으키지 않는 우아한 사용법으로 좋은 대답입니다. 배송이 아닌 코드를 판단하십시오. 또한 내 대답에서 프로토 타입 확장 프로그램을 제거하고 프로토 타입 확장을 제외하면 가장 많이 투표 된 답변과 정확히 일치하므로 -6이라는 사실은 투표를 한 사람들의 생각이 부족함을 나타냅니다. 그리고 최고 답변 전에 몇 달 게시되었습니다 ... 그래서 이것은 코드 콘테스트가 아닌 인기처럼 들립니다.
user2472643

-3

첫 번째 요소와 마지막 요소 만 교체해야하는 경우 :

array.unshift( array.pop() );

이 코드는 결함이 있습니다. 배열의 마지막 요소를 취한 다음 시작 부분에 놓고 스왑하지 않습니다. 이 코드는 다음을 수행합니다. [1, 2, 3] => [3, 1, 2]대신 [1, 2, 3] => [3, 2, 1].
David Archibald
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.