顯示具有 swap 標籤的文章。 顯示所有文章
顯示具有 swap 標籤的文章。 顯示所有文章

2014年2月6日 星期四

Ruby 併行賦值(Parallel Assignment)

前言

原本在找Ruby要怎麼交換兩個陣列的位置,找到一個很神奇的方法

class Array
    def swap!(a,b)
        self[a], self[b] = self[b], self[a]
        self
    end
end

完全看不懂在幹嘛,如果是C語言,在同一行裡使用逗號,則表示從右到左依次執行而已,例如:

int i,j;
for(i=0,j=5;i<10;i++,j--);

在C語言這個迴圈共執行10次,每次都執行i++與j--,我把i++與j--寫在一起用逗號分開,其實也可以這麼寫

int i,j;
for(i=0,j=5;i<10;){
    i++;
    j--;
}

有時候為了簡潔會塞在同一行。

可是Ruby這麼做,我全看不懂在幹嘛,在文章開頭的swap!函式裡頭,self[a]在我眼裡就是回傳self[a],然後將self[b]賦值self[b]等於沒變,最後再回傳self[a]而已,完全不清楚這是怎麼swap。

Parallel Assignment

查了一下ruby-doc.com之後,找到了Parallel Assignment這個關鍵字,終於搞清楚了,Ruby會將等號右邊所有的物件,按照相對位置賦值到等號左邊的參數,就叫做Parallel Assignment,譬如你要將x,y,z分別賦值1,2,3,在C語言你可能這麼寫

int x=1, y=2, z=3;

在Ruby裡面可以這麼寫

x,y,z = 1,2,3

就是如此而已,x,y,z就分別被賦值1,2,3。

當然,像我這種宅宅,一定還會好好地玩弄一下,我故意讓等號兩邊無法成對:

1: a,b = 1,2,3     # a=1, b=2
2: i,j,k = 1,2     # i=1, j=2, k=nil

行1,我原本以為b會被賦值為陣列[2,3],其實不用這麼古怪,Ruby設計直接把多出來的3丟掉,聰明的設計。

行2,我原本以為會出現錯誤訊息,但這也太嚴謹了,Ruby直接讓k=nil就行了,也是聰明的設計。

接著繼續惡搞一下,看他的語法有沒有靈活性:

a,b = c=1, 2            # a=1, b=2, c=1
a,b = c,d = 1, 2, 3     # Compiler Error
# 編譯錯誤 所以自己加上括號
a,b = (c,d = 1, 2), 3   # a=[1,2], b=3, c=1, d=2

有趣唷Parallel Assignment會回傳一個陣列,所以很靈活

SWAP

既然如此,我們就可以利用Parallel Assignment,來進行簡潔的swap,將x,y兩數交換:

# Parallel Assignment 定初值
x,y = 1,2   # x=1, y=2

# 一樣用Parallel Assignment技巧交換兩數
x,y = y,x # x=2, y=1

你想要3個數字一起交換也可以

x,y,z = 1,2,3   # x=1, y=2, z=3
x,y,z = y,z,x   # x=2, y=3, z=1

搞清楚之後,文章開頭提的那個陣列交換swap!函式就看得懂了

def swap!(a,b)
    self[a], self[b] = self[b], self[a]
    self
end

簡單將a,b兩個位置交換之後,最後把回傳陣列本身