JavaScriptスワップ配列要素


228

配列内の2つの要素を交換する簡単な方法はありますか?

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

回答:


412

一時変数は1つだけ必要です。

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

10年後、ハイジャックの編集を編集して、多くのES6を採用しました。

配列を指定するとarr = [1,2,3,4]、次のように1行の値を交換できます。

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

これは配列を生成し[2,1,3,4]ます。これは破壊的な割り当てです。


2
でも、ECMAScriptの6分割代入を利用せず、実際には一時変数に現在のスコープを汚染することなく、同時交換を達成することができますa = [b, b = a][0];@Janによって尖ったアウトとして、それはクロス言語(例えばC / Cだと、私はまだ自分自身が一時変数のアプローチを利用見つけるものの++ )そして、通常私の頭に浮かぶ最初のアプローチ。
Ultimater

3
他の人は、以下の示しとしてあなたはES6のある場所(のmutate)に交換することができます:[ list[y], list[x] ] = [ list[x], list[y] ];
protoEvangelion

[arr[0], arr[1]] = [arr[1], arr[0]][2, 1]残りのアレイなしでのみ生産
Palma

8
@YerkoPalma-式は[2,1]を返しますが、元の配列は[2,1,3,4]に変更されます
danbars

111

ネイティブJavaScriptを使用して単一の式が必要な場合は、スプライス操作からの戻り値に、削除された要素が含まれていることに注意してください。

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

1
A [x] = A.splice(y、1、A [x])[0]; ?in mootools Array.implement({swap:function(x、y){this [y] = this.splice(x、1、this [y])[0];}});

確認済み、[0]がありません。
ヨハンフィリップストラトハウゼン

素晴らしくて短いですが、@ aelgoaが言ったように、ほとんど遅くて単純なスワップ
ofir_aghai

75

これは大丈夫だと思います...

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

ハワーバーを使用して

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; return this;}});
ケン

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
関数でラップするだけで「潜在的なメモリリーク」を回避できませんか?
発がん性物質2016

3
潜在的な「平坦化」事故を回避するために、組み込み型のプロトタイプチェーンには触れません。
AaronDancer

54

よるとMetafilter上のいくつかのランダムな人、「Javascriptの最近のバージョンは、あなたがはるかにきれいに(とりわけ)スワップを行うことができ:」

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

私の簡単なテストでは、このPythonicコードは、現在「Google Apps Script」(「。gs」)で使用されているJavaScriptのバージョンでうまく機能することがわかりました。悲しいかな、さらなるテストは、このコードが「Uncaught ReferenceError:Invalid left-side side in assignment」を与えることを示しています。JavaScript( ".js")のどのバージョンでも、Google Chromeバージョン24.0.1312.57で使用されています。


2
これはES6の提案の一部です。まだ正式化されていないため、あらゆる場所で動作するとは限りません(動作するとしたら素晴らしいでしょう...)。
Isiah Meadows 2014

2
現在のfirefox最新バージョン(39.0.3)で動作します。
ジェイミー

2
Chromeバージョン54.0.2840.71以前のバージョンで動作します。また、babelなどのES6トランスパイラーを使用する場合は、これがお勧めのコードになります。
amoebe

3
このソリューションが大好きです。意図したとおりにきれいにします。9年前に質問があまりにも悪い…
DavidsKanal

2
これはes6で標準化されており、この機能は構造化解除と呼ばれます。
AL-zami 2018

29

まあ、あなたは両方の値をバッファリングする必要はありません-1 つだけ:

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

13
あなたの 'tmp'は 'b'よりも使いやすいように聞こえます
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
ベイダーのようにそれはダースですか?+1
krosenvold 2009年

7
何かが間違っている。とlist[y] = list[x] - list[x];同じではないlist[y] = 0;ですか?
ErikE

3
xorトリックは、x = yの場合も失敗します。list[x]を元の値のままにしておくことが期待できる場合、list [x]をゼロに設定します。
David Cary

1
技術的には、一時的な値を作成するだけで、配列の関連する領域の外には移動しません。
Mark Smit 2015

1
どちらも単純でも効率的でも一般的でもありません。
LoganMzz 2017

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]];
stromaの


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

3番目の変数を定義する必要のない、このようなソリューションを検討してください。

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

次のような単純な識別関数を使用して、オブジェクトやリテラルをいくつでも入れ替えることができます。

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は、関数に渡された後に発生します。


ハック...しかし、関数を1回だけ使用する場合は、もう1つうまくいくでしょう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 2014

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

スワッピングには興味深い方法が1つあります。

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


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))

これは一時変数の方法よりも効率的ではありません。3回スライスされ、3つのスライスされた配列の間の2つのオブジェクトと連結された変更された配列を効果的に返します。単純に配列に割り当てる値を取得するために必要なメモリの2倍を超えるメモリを効果的に必要としました(そのいずれも行われていません)。
Isiah Meadows 2014

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

簡潔にするために、ここでは醜いワンライナーバージョンを示します。このバージョンは、上記のすべての連結およびスライスよりも少しだけ醜くありません。受け入れられた答えは本当に行く方法であり、より読みやすい方法です。

与えられた:

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

2つのインデックス(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で一時変数を使用したくない場合、これは配列要素を交換する1つの方法です。

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要素が削除された配列を返すため、2つの新しい配列を作成します。developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
XCS

もっと上手にできる方法はありますか?@Cristy
venkat7668

受け入れられる答えは簡単なものです。これは、変数宣言の数に制限がある場合に便利です(主にインタビューの目的:))。しかし、あなたが言ったようにメモリ効率が良くありません。@Cristy
venkat7668

私は個人的にはそれは悪い習慣であり、初心者には勧めるべきではないと思います。読むのもとても難しいです。
XCS 2019年

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を使用すると、次のように実行できます...

あなたがこれらの2つのアレイを持っていると想像してください ...

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
ごちゃごちゃ、ごめんなさい、時々ペアになっていない^ _ ^
user2472643

2
回答のコンテキストで問題を説明しているのはあなただけです...負のスコアは、最初は機能しない回答のために予約する必要があります。次に、これは競合を引き起こさないエレガントな使用法での良い答えです。配信ではなくコードを判断します。また、私の回答では、それを削除してプロトタイプ拡張を除外した場合、最も投票された回答とまったく同じになるため、これが-6であるという事実は、投票した人々からの考えの欠如を示しています。そして、トップアンサーの数か月前に投稿されたので、これはコードコンテストではなく人気のように聞こえます。
user2472643 2017

-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.