Groovy で swap

http://www.fepc.or.jp/present/jigyou/japan/
によると 0〜8 時が消費電力の少ない時間帯みたいだ。というわけで深夜プログラミング中

単純な変数の場合

Groovy には Multiple Assignment があるので単純な変数の swap は簡単に行える。
http://groovy.codehaus.org/Statements から

// given those two variables
def a = 1, b = 2

// swap variables with a list
(a, b) = [b, a]

assert a == 2
assert b == 1

ただし http://groovy.codehaus.org/Multiple+Assignment で注記されているように、以下の場合は Multiple Assignment できない。*1

  • "." や "[" を含む場合
  • フィールド定義の場合

単純な変数でない場合

List の場合は Collections.swap で要素を入れ替えることができる。

def list = [1, 2]
Collections.swap(list, 0, 1)
assert [2, 1] == list


Map の場合は Object#with を使えば単純な変数で表現できるので入れ替えることができる。

def map = [x:1, y:2]
map.with {
  (x, y) = [y, x]
}
assert [x:2, y:1] == map


http://groovy.codehaus.org/Multiple+Assignment の例も with を使えば可能だったりする。

(p.firstname, p.lastname) = "My name".split()        // ng
p.with { (firstname, lastname) = "My name".split() } // ok

一時変数を使わない方法

『C 言語による最新アルゴリズム事典』 から
当然、Groovy に限らないが Groovy で書いてみる。

def (x, y) = [1, 2]

// 排他的論理和
y ^= x  // x ^ y
x ^= y  // x ^ x ^ y = y
y ^= x  // x ^ y ^ y = x

assert [2, 1] == [x, y]

// 差
y = x - y
x -= y  // x - (x - y) = y
y += x  // (x - y) + y = x

assert [1, 2] == [x, y]

// 商
y = x / y
x /= y  // x / (x / y) = y
y *= x  // (x / y) * y = x

assert [2, 1] == [x, y] // x, y は BigDecimal

*1:パースエラーになる