陣列型態


在Ruby中,陣列為有序的物件集合,具有索引特性,長度可以變動。要建立陣列,可以使用[]實字,串列中每個元素,使用逗號 , 區隔。例如:
>> array1 = []
=> []
>> array1 << 1
=> [1]
>> array1 << "two"
=> [1, "two"]
>> array1 << true
=> [1, "two", true]
>> array1.pop
=> true
>> array1
=> [1, "two"]
>> array1.delete("two")
=> "two"
>> array1
=> [1]
>> array1.insert(0, "three")
=> ["three", 1]
>> array2 = [1, "two", true]
=> [1, "two", true]
>> array2.reverse
=> [true, "two", 1]
>> array2.include? "two"
=> true
>> array2.length
=> 3
>>

使用[]建立陣列物件,為Array的實例,若沒有指定任何元素,長度為0。你可以對陣列使用push(相當於使用<<操作)、poplast方法對末端進行附加、取出、讀取元素,也就是進行堆疊(Stack)操作。使用unshiftshiftfirst對前端進行加入、取出、讀取元素,也就是進行佇列(Queue)操作。可以使用insertdeletereverse等方法進行安插、刪除、反轉等動作,使用include?測試元素是否在陣列中,使用length取得陣列長度。

如果要對陣列中的元素進行排序,可以使用sort方法。例如:
>> array = [3, 1, 4, 5, 2, 7]
=> [3, 1, 4, 5, 2, 7]
>> array.sort
=> [1, 2, 3, 4, 5, 7]
>> array.sort { |a, b| b <=> a }
=> [7, 5, 4, 3, 2, 1]
>>


sort方法可以自行指定排序方式,上例中第二個sort範例,{} 區塊中會傳入陣列中兩元素給a、b參考,你要傳回0、大於0或小於0,表示順序上a等於b、a大於b及a小於b,<=>操作左邊若大於右邊會傳回1,等於右邊會傳回0,小於右邊會傳回-1,在Ruby區塊中,最後一個運算的結果會作為傳回值,因此第二個sort範例就完成陣列中反序排列。

如果要附加多個元素,則可以使用+操作,注意與<<操作的不同。例如:
>> array1 = [1, 2, 3]
=> [1, 2, 3]
>> array1 << [4, 5, 6]
=> [1, 2, 3, [4, 5, 6]]
>> array2 = [1, 2, 3]
=> [1, 2, 3]
>> array2 + [4, 5, 6]
=> [1, 2, 3, 4, 5, 6]
>>


可以對陣列使用*,指定加倍陣列的內容,注意對每個元素是進行淺層複製(Shallow copy)
>> array1 = [[1, 2, 3], [4, 5, 6]]
=> [[1, 2, 3], [4, 5, 6]]
>> array2 = array1 * 2
=> [[1, 2, 3], [4, 5, 6], [1, 2, 3], [4, 5, 6]]
>> array2[0][0] = 100
=> 100
>> array2
=> [[100, 2, 3], [4, 5, 6], [100, 2, 3], [4, 5, 6]]
>> array1
=> [[100, 2, 3], [4, 5, 6]]
>>


*也可以用來拆解陣列,如果你要將陣列中的元素一次指定給數個變數時會很方便:
>> x, y, z = *[10, 20, 30]
=> [10, 20, 30]
>> x
=> 10
>> y
=> 20
>> z
=> 30
>>
x, y, z = [40, 50, 60]
=> [40, 50, 60]
>> x
=> 40
>> y
=> 50
>> z
=> 60
>>

實際上可以看到,如果只是指定給變數,並不需要特別加上*,之後會看到,如果要將陣列指定給 方法 上的參數,才需要特別指定*。

*也可以用來收集資料為陣列,例如:
>> *a = 1, 2, 3
=> [1, 2, 3]
>> a = [1, 2, 3]
=> [1, 2, 3]
>> a = 1, 2, 3
=> [1, 2, 3]
>>

可以看到,實際上要收集資料為陣列,只要在等號右邊以逗號區隔就可以了,結合以上說明,在Ruby中要交換變數,只要這麼作:
>> x = 10
=> 10
>> y = 20
=> 20
>> x, y = y, x
=> [20, 10]
>> x
=> 20
>> y
=> 10
>>

因為=右邊若有逗號區隔的資料,會收集為陣列,陣列若指定給右邊變數,會拆解並分配給各個變數,因而組成了簡單的交換變數語法。

在Ruby中,陣列可以進行集合(Set)運算,使用&可作交集運算,使用|可作聯集運算,使用-作減集運算。例如:
>> admins = ["Justin", "caterpillar"]
=> ["Justin", "caterpillar"]
>> users = ["momor", "hamini", "Justin"]
=> ["momor", "hamini", "Justin"]
>> admins & users
=> ["Justin"]
>> admins | users
=> ["Justin", "caterpillar", "momor", "hamini"]
>> admins - users
=> ["caterpillar"]
>>


陣列不提供XOR運算,不過可以自己製作一個:
>> class Array
>>     def ^(that)
>>         self + that - (self & that)
>>     end
>> end
=> nil
>> admins = ["Justin", "caterpillar"]
=> ["Justin", "caterpillar"]
>> users = ["momor", "hamini", "Justin"]
=> ["momor", "hamini", "Justin"]
>> admins ^ users
=> ["caterpillar", "momor", "hamini"]
>>
 

在上面兩個範例中,亦示範了陣列於集合的應用方式之一,利用集合依序測試,同時是站長也是使用者的有誰(admins & users)?站長與使用者有哪些人(admins | users)?站長中不是使用者的有誰(admins - users)?沒有同時具備站長與使用者身份的有誰(admins ^ users)?

你也可以直接使用[]指定索引來取得元素、修改元素甚至安插元素,索引可以是負數,也可以進行切片(Slice)運算。例如:
>> array = ["one", "two", "three", "four"]
=> ["one", "two", "three", "four"]
>> array[0]
=> "one"
>> array[0] = 1
=> 1
>> array
=> [1, "two", "three", "four"]
>> array[1..3]
=> ["two", "three", "four"]
>> array[1...3]
=> ["two", "three"]
>> array[1..2] = [2, 3]
=> [2, 3]
>> array
=> [1, 2, 3, "four"]
>> array[-1]
=> "four"
>> array[-2]
=> 3
>> array[1, 3]
=> [2, 3, "four"]
>> array[1, 9]
=> [2, 3, "four"]
>> array[1, -1]
=> [2, 3, "four"]

>> array[1..9]
=> [2, 3, "four"]
>> array[1, 3] = ["two", "three", 4]
=> ["two", "three", 4]
>> array
=> [1, "two", "three", 4]
>> array[1, 0] = [2, 3]
=> [2, 3]
>> array
=> [1, 2, 3, "two", "three", 4]
>> array[1..0] = ["two", "three"]
=> ["two", "three"]
>> array
=> [1, "two", "three", 2, 3, "two", "three", 4]
>>


[n..m]可 指定起始索引與結束索引,且包括結束索引以取得元素,如果結束索引超出了陣列範圍,就是直接取到最後一個索引元素, [n...m]可 指定起始索引與結束索引,但包括結束索引以取得元素(實際上n..m或n...m建立了Range實例,之後會再說明)。[n, length]可指定起始索引與長度取得元素,如果長度超出了剩餘長度,就是直接取到最後一個元素。[n..m]、[n...m]或[n, length]右邊接上=,表示作取代的動作,如果指定了[n..0]、[n...0]或[n, 0],則是技巧性地作了安插的動作。

你也可以使用Array.new方式建立陣列。例如:
>> array = Array.new(5)
=> [nil, nil, nil, nil, nil]
>> array = Array.new(5, 10)
=> [10, 10, 10, 10, 10]
>> array = Array.new(5, [1, 2, 3])
=> [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
>> array[0][0] = "one"
=> "one"
>> array
=> [["one", 2, 3], ["one", 2, 3], ["one", 2, 3], ["one", 2, 3], ["one", 2, 3]]
>>


Array.new第一個參數為陣列長度,第二個為每個索引預設元素,如果沒有指定則預設為nil,注意Array.new(5, [1, 2, 3])的陷阱,實際上五個索引都會參考至同一個[1, 2, 3]物件,如果你希望五個索引參考至不同的陣列物件,必須如下:
>> array = Array.new(5) {
?>     [1, 2, 3]
>> }
=> [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
>> array[0][0] = "one"
=> "one"
>> array
=> [["one", 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
>>


使用Array.new時,區塊中最後一個運算的結果會作為傳回值,上例中,會執行五次區塊內容,每次依陣列實字(Array literal)產生一個新的[1, 2, 3]陣列,因此五個索引就會參考不同的陣列物件。

如果想得知目前是要建立第幾個索引的元素,可以如下:
>> array = Array.new(5) { |index|
?>     index
>> }
=> [0, 1, 2, 3, 4]
>>


如果想循序走訪元素,可以有幾個方式:
>> array = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> array.each do |element|
?>     puts element
>> end
1
2
3
4
5
=> [1, 2, 3, 4, 5]
>> for element in array
>>     puts element
>> end

1
2
3
4
5
=> [1, 2, 3, 4, 5]
>> for index in 0..4
>>     puts array[index]
>> end
1
2
3
4
5
=> 0..4
>> array.each_with_index do |element, index|
?>     puts "(%d, %d)" % [element, index]
>> end
(1, 0)
(2, 1)
(3, 2)
(4, 3)
(5, 4)
=> [1, 2, 3, 4, 5]
>>


如果要建立字串陣列,有個方便的%w可以使用。例如:
>> %w[Python JavaScript Ruby]
=> ["Python", "JavaScript", "Ruby"]
>>


用來包括元素內容的符號,不一定要用[],也可以使用自己想用的符號,以不與字串中字元重複為原則。例如:
>> %w<Python JavaScript Ruby>
=> ["Python", "JavaScript", "Ruby"]
>> %w|Python JavaScript Ruby|
=> ["Python", "JavaScript", "Ruby"]
>>