Code Tips‎ > ‎

JavaScript - 二つの変数を交換する方法

一般的な方法

二つの変数の交換で最も一般的な方法は、作業用変数を使った方法でしょう。
// 作業用変数を使った交換
tmp = a;
a = b;
b = tmp;
わかりやすいので仕事で書くコードなどでは原則この書き方にすべきです。


作業用変数を使う理由は、代入時に値が上書きされてしまうからです。例えば以下のように書くと
a = b; // (1)
b = a; // (2)
(1)の時点でaとbが同じ値になってしまうため交換ができません。


特徴をまとめるとこんな感じです。
  • あらゆるオブジェクトに対応可能
  • 作業用変数が必要
  • 3行(文)で表現
  • JavaScript以外の言語でも利用可能

作業用変数を使わない少し変わった方法

ただ、それではつまらないので、少し変わった書き方を紹介します。昔から有名なのは加減算を使った方法とXOR演算子を使った方法です。

// 加減算による交換
b = a - b;
a -= b;
b += a;
// XOR演算子による交換
b ^= a;
a ^= b;
b ^= a;
「作業用変数を使ってはいけない」という制約がある場合(そんなケースがあるのか?)や、あえてコードをわかりにくくしたい場合には有効でしょう。JavaScript以外の言語でも利用できます。

この2つの方法とも、整数とboolean型にしか対応できません。「加減算による交換」は小数の場合にうまく交換できる場合もありますが、桁落ちして誤差が出る場合もあります(例えば「1と0.1」の交換で失敗します)。なので、利用できる場面が限られてくるでしょう。

一応、以下のように2行(文)で表現する事も可能です。
// 加減算による交換
b = a - b;
b += a -= b;
// XOR演算子による交換
b ^= a;
b ^= a ^= b;

特徴をまとめると以下です。
  • 整数とboolean型のみで利用できる
  • 作業用変数が不要
  • 3行(文)で表現。2行(文)で表現も可能
  • JavaScript以外の言語でも利用可能

加減算による交換・XOR演算子による交換の確認

加減算による交換」と「XOR演算子による交換」の正当性は式を変形する事により確認できます。

まず、加減算による交換について。複合代入演算子を使わずに記述するとこうなります。
// 加減算による交換
b = a - b; // (1)
a = a - b; // (2)
b = b + a; // (3)

(1)でbに「a - b」が代入されています。その結果をふまえて(2)を変換すると以下になります。
a = a - (a - b);
つまり以下になります。
a = b;

同様に(1)・(2)の結果をふまえて(3)を変換すると、以下になります。
b = (a - b) + b;
つまり以下になります。
b = a;
a, bの値が互いに交換できていることが確認できました。こうして考えてみると意外と簡単ですね。


XOR演算子による交換も考えてみましょう。
// XOR演算子による交換
b = a ^ b; // (1)
a = a ^ b; // (2)
b = b ^ a; // (3)

(1)でbに「a ^ b」が代入されています。その結果をふまえて(2)を変換すると以下になります。
a = a ^ (a ^ b);
つまり以下になります。
a = b;

同様に(1)・(2)の結果をふまえて(3)を変換すると、以下になります。
b = (a ^ b) ^ b;
つまり以下になります。
b = a;
XOR演算子を使っているから難しそうと感じるかもしれませんが、加減算を使った方法とほぼ同じです。確認してみれば簡単な事ですね。

乗除算による交換

さらにさらに、乗除算でも不可能ではありません。
b = a / b;
a /= b;
b *= a;

ただし、交換する値に0が含まれるとゼロ除算が発生してしまうので、正しく交換することは出来ません。また、値により丸め誤差や情報落ちなどにより交換後の値に誤差が生じることもあります。

ですので、現実にはこのロジックを利用するケースはまずないと思います。面白ロジックのひとつとして覚えておくにとどめておいたほうがよさそうです。万が一使ってみたいという場合には上記の点について注意をしてください。

作業用変数を使わないとても変わった方法

極めつけはこれです。1行で表現しています!

// 配列の性質を応用した交換
a = [b, b = a][0];

ただし、この書き方はJavaScriptでしか利用できません(これを紹介したくてこのページを作りました)

まず「[b, b = a]」の部分で配列を定義しています。配列の1番目の項目をbの値で初期化しています。この項目の値はたとえbの内容が変わったとしても変わりません。

次に、配列の2番目の項目を「b = a」で初期化しています。「b = a」はbにaを代入した結果、つまりaの値で初期化されるわけですが、「bにaを代入すること」だけが目的です。この時点で、変数a, bともに、「最初にaに代入された値」になっています。

そして最後に「[0]」の部分で、配列の1番目の項目、つまりもともとbに入っていた値を取り出し、aに代入して終わりです。


これだと、
  • あらゆるオブジェクトに対応可能
  • 作業用変数が不要
  • 1行(文)で表現
  • JavaScriptだけでしか利用できない
という特徴があります。

人をびっくりさせたいときには有効でしょう。仕事で使うことは難しいと思いますが、JavaScriptの基本的な性質をうまく利用した面白コードだと思います。


2013/09/05