ActionScript 2.0/陣列簡介
關鍵概念
- 索引陣列與關聯陣列
- Array 建構函式和陣列字面量
- 巢狀陣列
- 陣列連線
- 向陣列新增和刪除元素
- 彈出、推入、移位和不移位
- 拼接
- 透過切片提取陣列元素
- 陣列和字串之間的相互轉換
- 陣列排序
- 對數字和字串進行排序
- 自定義標準
- 返回索引
- 按欄位排序
- 反轉陣列
我們在控制語句章節中瞭解了陣列。但是,我們沒有學習如何操作它們。這是我們本章的重點。
在計算機程式設計中,實際上存在兩種型別的陣列,索引陣列和關聯陣列(也稱為雜湊)。在索引陣列中,每個陣列元素都有一個索引,而在關聯陣列中,每個陣列元素都有一個名稱。在 ActionScript 中,Array 類生成索引陣列,而 Object 類生成關聯陣列。
在關於控制語句的章節中,我們已經介紹了 Array 類建構函式在沒有引數的情況下使用,我們將在本章中不再重複。在本章中,我們將介紹使用建構函式的另外兩種方式,以及陣列字面量。(是的,陣列也有字面量!)
| 程式碼 | 結果 |
|---|---|
var dogs:Array = new Array(10);
dogs[0] = "Spot";
dogs[1] = "Lucky";
dogs[2] = "Max";
...
dogs[9] = "Rover";
trace(dogs[0]);
var fruits:Array = new Array("Apples", "Bananas", "Oranges", "Pears");
trace (fruits[2]);
var months:Array = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"];
trace(months[9]);
|
|
在第一個例子中,我們透過指定長度來初始化 dogs 陣列,然後為每個元素分配一個字串值。在第二個例子中,我們將值直接放入建構函式中。[1] 在第三個例子中,我們使用了陣列字面量。陣列字面量總是用一對方括號括起來,每個元素之間用逗號隔開,例如:[1,1,3,5,8,13,21,34]。
多維陣列或巢狀陣列是指包含陣列作為元素的陣列。它可以以表格形式表示資料。例如
| 程式碼 | 結果 |
|---|---|
var multiplicationTables:Array = new Array(10);
for(var i:Number = 0; i < multiplicationTables.length; i++){
multiplicationTables[i] = new Array(10);
for(var j:Number = 0; j < multiplicationTables[i].length; j++){
multiplicationTables[i][j] = i * j;
}
trace(multiplicationTables[i]);
}
|
|
一旦我們學習了動態影片剪輯和文字欄位的建立以及繪圖 API,我們就可以實際將此陣列呈現為表格。
幸運的是,我們可以使用陣列字面量來建立巢狀陣列的快捷方式
| 程式碼 | 結果 |
|---|---|
var someNestedArray:Array = new Array([1, 3, 5, 7, 9], [1, 1, 2, 3, 5], [2, 4, 6, 8, 10]);
trace(someNestedArray[0]);
trace(someNestedArray[1]);
trace(someNestedArray[2]);
trace(someNestedArray);
|
|
請注意,在最後一個跟蹤中,多維陣列在轉換為字串並跟蹤時被“展平”了。我們可以使用 split 方法建立一個完全展平的陣列
| 程式碼 | 結果 |
|---|---|
var someNestedArray:Array = new Array([1, 3, 5, 7, 9], [1, 1, 2, 3, 5], [2, 4, 6, 8, 10]);
var someFlattenedArray:Array = String(someNestedArray).split(",");
trace(someFlattenedArray.length);
|
|
由於長度為 15,因此有 15 個元素,而不是三個元素,每個元素包含五個元素。
連線兩個陣列是一個相當簡單的操作。它需要使用 array1.concat(array2, array3...) 方法。此方法不會展平巢狀陣列。以下程式碼將兩個數組合並在一起
| 程式碼 | 結果 |
|---|---|
var array1:Array = new Array("a", "b", "c");
var array2:Array = new Array("d", 5, "f");
var array3:Array = array1.concat(array2);
trace(array3);
|
|
concat() 不應與稍後介紹的 join() 混淆。
有幾種方法可以向陣列新增和刪除元素
- array.pop()
- array.push(object1, object2...)
- array.shift()
- array.unshift(object1, object2...)
- array.splice(第一個元素的索引, [元素數量,] [object1, object2...])
這開始變得有點嚇人,所以讓我們逐個介紹它們。
pop() 從陣列中刪除最後一個元素,然後返回彈出的元素。此示例將展示“pop”方法的工作原理
| 程式碼 | 結果 |
|---|---|
var myArray = new Array(1, 2, 3, 4);
var popped:Number = myArray.pop();
trace(popped);
trace(myArray);
|
|
首先,我們宣告 'myArray' 陣列,其中包含四個元素:1、2、3 和 4。接下來,我們宣告 'popped' 變數。然後,我們彈出 'myArray' 並將最後一個元素分配給 'popped' 變數。然後,我們跟蹤 popped 以檢視彈出的元素,然後跟蹤新陣列。
push() 向陣列末尾新增一個或多個元素,然後返回新陣列的長度
| 程式碼 | 結果 |
|---|---|
var myArray = new Array(1, 2);
var newLength:Number = myArray.push(3, 4);
trace(newLength);
trace(myArray);
|
|
我們首先宣告 'myArray' 陣列,其中包含兩個元素,1 和 2。第二行將值 3 和 4 推入 myArray(返回新長度),宣告 'newLength' 變數,然後將新長度分配給 newLength。
移位和不移位類似於彈出和推入,但元素是從陣列的開頭新增和刪除,而不是結尾。
以下是如何移位的示例
| 程式碼 | 結果 |
|---|---|
var myArray = new Array(1, 2, 3, 4);
var shifted:Number = myArray.shift();
trace(shifted);
trace(myArray);
|
|
首先,我們宣告 'myArray' 陣列,其中包含四個元素:1、2、3 和 4。接下來,我們宣告 'shifted' 變數。然後,我們移位 'myArray' 並將第一個元素分配給 'shifted' 變數。然後,我們跟蹤 shifted 以檢視移位的元素,然後跟蹤新陣列。
以下是如何不移位的示例
| 程式碼 | 結果 |
|---|---|
var myArray = new Array(3, 4);
var newLength:Number = myArray.unshift(1, 2);
trace(newLength);
trace(myArray);
|
|
我們首先宣告 'myArray' 陣列,其中包含兩個元素,3 和 4。第二行將值 1 和 2 不移位到 myArray(返回新長度),宣告 'newLength' 變數,然後將新長度分配給 newLength。
拼接陣列比推入、彈出、移位和不移位更靈活,更復雜。(切片、拆分、拼接、移位……糊塗了嗎?)拼接是同時從陣列中刪除和新增元素的過程。splice() 方法向陣列新增元素並從陣列中刪除元素,然後返回刪除的元素。
讓我們再看看引數
array.splice(index of the first element, [number of elements], [new element 1, new element 2...])
如您所見,只有第一個引數是必需的。第一個引數指示您要開始執行刪除和新增操作的位置。它可以是普通索引(0、1、2、3……),也可以是負數(-1 作為最後一個元素,-2、-3、-4……)。如果這是您包含的唯一引數,則將從該引數開始刪除所有元素
| 程式碼 | 結果 |
|---|---|
var myArray:Array = [1, 2, 3, 4];
myArray.splice(2);
trace(myArray);
|
|
第二個引數是要刪除的元素數量。讓我們修改上面的示例,只刪除 3
| 程式碼 | 結果 |
|---|---|
var myArray:Array = [1, 2, 3, 4];
myArray.splice(2, 1);
trace(myArray);
|
|
其餘引數是要新增到陣列中的元素,以替換刪除的元素。
| 程式碼 | 結果 |
|---|---|
var myArray:Array = [1, 2, 3, 4];
myArray.splice(2, 1, 6, 7, 8);
trace(myArray);
|
|
我們也可以將第二個引數設定為 0,這樣我們就可以新增元素,而不會刪除任何元素
| 程式碼 | 結果 |
|---|---|
var myArray:Array = [1, 2, 3, 4];
myArray.splice(2, 0, 6, 7, 8);
trace(myArray);
|
|
slice() 返回陣列中的某些元素。以下是 slice() 的引數
array.slice([index of the first element], [index of the last element]);
兩個引數都是可選的。如果兩個元素都為空,則複製整個陣列
| 程式碼 | 結果 |
|---|---|
var myArray:Array = [1, 2, 3, 4];
var secondArray:Array = myArray.slice();
secondArray.pop();
trace(secondArray);
trace(myArray);
var thirdArray:Array = myArray;
thirdArray.pop();
trace(thirdArray);
trace(myArray);
|
|
再次強調,整個陣列是複製,而不是連結。在上面的例子中,改變 secondArray 不會改變原始的 myArray,因為 myArray 被複制到了 secondArray。然而,改變 thirdArray 會改變原始的 myArray,因為 thirdArray 只包含指向 myArray 的連結,而不是 myArray 的副本。
讓我們再試一次,這次使用第一個引數
| 程式碼 | 結果 |
|---|---|
var myArray:Array = [1, 2, 3, 4, 5];
var slicedArray:Array = myArray.slice(2);
trace(slicedArray);
|
|
只從元素 2 開始的所有內容都被複制到 slicedArray。現在讓我們第三次嘗試,使用兩個引數
| 程式碼 | 結果 |
|---|---|
var myArray:Array = [1, 2, 3, 4, 5];
var slicedArray:Array = myArray.slice(2, 3);
trace(slicedArray);
|
|
只從元素 2 到元素 3 的元素被複制到 slicedArray。
有時,我們希望將一個字串分割成多個由分隔符(一個符號,指示我們應該在何處分割字串)分隔的子字串,然後將每個子字串放入一個數組中。在這種情況下,我們需要使用 split 方法
| 程式碼 | 結果 |
|---|---|
trace("Foo + Bar + Baz + Qux".split(" + "));
trace("Foo + Bar + Baz + Qux".split(" + ", 3));
trace("Foobar".split(""));
|
|
在第一個跟蹤中,我們使用 " + " 作為分隔符來建立一個包含元素 Foo、Bar、Baz 和 Qux 的陣列。在第二個跟蹤中,我們將子字串的數量限制為 3。在第三個跟蹤中,分隔符是一個空字串,因此每個子字串都包含一個字元。
連線陣列是分割字串的逆運算。它使用陣列元素和某個分隔符(第一個也是唯一的引數)建立一個新的字串
| 程式碼 | 結果 |
|---|---|
trace(["Foo", "Bar", "Baz", "Qux"].join(" + "));
trace(["F", "o", "o", "b", "a", "r"].join(""));
trace(["Foo", "Bar", "Baz", "Qux"].join());
|
|
在第一個跟蹤中,我們使用 " + " 將 Foo、Bar、Baz 和 Qux 連線成一個字串。在第二個跟蹤中,我們得到了單詞 "Foobar",因為我們使用空字串作為分隔符。在第三個跟蹤中,我們產生了與 trace(String(["Foo", "Bar", "Baz", "Qux"].join())); 相同的效果,因為我們沒有指定任何分隔符,並且使用了預設的逗號。
在 ActionScript 中,排序是一個非常複雜的主題。在本節中,我們將嘗試做到這一點!
sort() 函式可以使用一個條件進行排序。
排序一堆字串的最簡單方法是使用 Unicode 程式碼點。(我們早在關於運算子的章節中討論過 Unicode 程式碼點。)這不需要任何引數
| 程式碼 | 結果 |
|---|---|
var myArray:Array = ["spot", "lucky", "Rover", "Max"];
myArray.sort();
trace(myArray);
myArray = [1, 300, 2, 4, 6];
myArray.sort();
trace(myArray);
|
|
請注意,Lucky 和 Max 在 rover 和 spot 之前,因為大寫字母在 Unicode 中排在小寫字母之前。還要注意,數字也是根據它們的 Unicode 程式碼點排序,而不是它們的幅度或值。
如果我們希望排序忽略大小寫,我們可以將一個 Array 類常量 Array.CASEINSENSITIVE 傳遞給 sort() 函式
| 程式碼 | 結果 |
|---|---|
var myArray:Array = ["spot", "lucky", "Rover", "Max"];
myArray.sort(Array.CASEINSENSITIVE);
trace(myArray);
|
|
Array.CASEINSENSITIVE 可以用數字 1 替換。
正如我們上面所看到的,sort() 預設情況下將元素作為字串排序。要排序數字,我們需要將另一個 Array 類常量 Array.NUMERIC 傳遞給 sort() 函式
| 程式碼 | 結果 |
|---|---|
var myArray:Array = [1, 300, -Infinity, 2, 4, 4.3e-3, Infinity, -3, 6, 0x2A];
myArray.sort(Array.NUMERIC);
trace(myArray);
|
|
請注意,負無窮大總是最小值,無窮大總是最大值。Array.NUMERIC 可以用數字 16 替換。
有時,使用 Unicode 程式碼點還不夠。在這種情況下,我們必須建立自己的函式。sort() 函式的第一個引數是一個包含兩個引數的函式,它們決定兩個值中的哪個應該排在前面。如果第一個引數排在第二個引數前面,該函式應該返回 1;如果第二個引數排在第一個引數前面,則返回 -1;如果無關緊要,則返回 0。如果聽起來很複雜,請檢視此示例
| 程式碼 | 結果 |
|---|---|
var myArray:Array = ["a good dog called spot", "a canine called lucky",
"a cute mammal called Rover", "an adorable animal called Max"];
function whichComesFirst(a:String, b:String):Number{
var dog1:String = a.substring(a.lastIndexOf(" ")+1).toUpperCase();
var dog2:String = b.substring(b.lastIndexOf(" ")+1).toUpperCase();
if(dog1 > dog2){
return 1;
} else if(dog1 < dog2) {
return -1;
} else {
return 0;
}
}
myArray.sort(whichComesFirst);
trace(myArray);
|
|
在 whichComesFirst 函式中,我們首先從字串中提取了最後一個單詞。然後,我們在比較之前將所有內容轉換為大寫。這樣,大小寫就被忽略了。此函式按照真正的字母順序對陣列進行排序,類似於我們使用 Array.CASEINSENSITIVE 達到的效果。
要以降序排序,我們將值 Array.DESCENDING 傳遞給第一個引數
| 程式碼 | 結果 |
|---|---|
var myArray:Array = ["spot", "lucky", "Rover", "Max"];
myArray.sort(Array.DESCENDING);
trace(myArray);
|
|
這也適用於自定義標準(請注意,比較函式是第一個引數,陣列常量是第二個引數)。
| 程式碼 | 結果 |
|---|---|
var myArray:Array = ["a good dog called spot", "a canine called lucky",
"a cute mammal called Rover", "an adorable animal called Max"];
function whichComesFirst(a:String, b:String):Number{
var dog1:String = a.substring(a.lastIndexOf(" ")+1).toUpperCase();
var dog2:String = b.substring(b.lastIndexOf(" ")+1).toUpperCase();
if(dog1 > dog2){
return 1;
} else if(dog1 < dog2) {
return -1;
} else {
return 0;
}
}
myArray.sort(whichComesFirst, Array.DESCENDING);
trace(myArray);
|
|
如果我們已經有了另一個數組常量作為引數,我們應該使用按位或運算子 (|)[2] 來分離兩個陣列常量。
| 程式碼 | 結果 |
|---|---|
var myArray:Array = [1, 300, -Infinity, 2, 4, 4.3e-3, Infinity, -3, 6, 0x2A];
myArray.sort(Array.NUMERIC | Array.DESCENDING);
trace(myArray);
|
|
陣列常量 Array.RETURNINDEXEDARRAY 將使 sort() 返回一個包含每個數字的新索引的陣列。例如,如果原始陣列是 [3, -1, 4],則 sort() 將返回 [1, 0, 2],其中 3 是排序陣列中的第二個數字(索引 1),-1 是第一個數字(索引 0),4 是第三個數字(索引 2)。
| 程式碼 | 結果 |
|---|---|
var myArray:Array = [1, -3, 5, 7, 3];
var myIndices:Array = myArray.sort(Array.NUMERIC | Array.RETURNINDEXEDARRAY);
trace(myIndices);
var mySortedArray:Array = new Array();
for(i = 0; i < myIndices.length; i++){
mySortedArray[i] = myArray[myIndices[i]];
}
trace(mySortedArray);
|
|
請注意,資料庫中的術語略有不同。在資料庫中,myIndices 被稱為索引,而我們的陣列索引被稱為索引鍵。在這本書中,為了避免混淆,我們將避免使用這些術語。
如果您使用 Array.UNIQUESORT 常量,如果發現兩個或多個元素等效,Flash 將返回 0 而不是修改陣列。我們將在第四節中使用此常量,屆時我們將學習異常處理。
有時,我們希望對陣列中的雜湊或物件進行排序,而使用 sort() 以及自定義的排序條件則顯得過於繁瑣。這時,sortOn() 就可以派上用場。
sortOn 將陣列視為資料庫中的表格。在資料庫中,表格 是一個實體或記錄的集合,這些實體或記錄具有相同的記錄結構。每個實體都有若干欄位,每個欄位都儲存記錄的特定屬性。有時,我們需要使用查詢 以特定的方式對欄位進行排序。排序鍵 是用於排序的欄位。主要排序鍵 首先用於對資料進行排序。當兩個或多個數據在某個欄位中具有相同的屬性時,將使用次要排序鍵 對這些資料進行排序。如果仍然存在等效值,則使用三級排序鍵,依此類推。
假設我們有一個包含關於多本書籍資料的表格。我們想要按書名降序排列書籍標題。如果存在兩本書具有相同的書名,則按作者姓氏升序排列,然後按作者名升序排列,最後按出版年份降序排列。在 SQL 中,執行此操作的語法為
SELECT *
FROM Books
ORDER BY Title DESC, Author_last ASC, Author_first ASC, Pub_year DESC;
即使您對 SQL 一無所知,您也可能理解其中一部分程式碼。不幸的是,對於 ActionScript 而言,情況要複雜得多。讓我們嘗試將這段 SQL 程式碼改寫為 ActionScript 程式碼
| 程式碼 | 結果 |
|---|---|
var books:Array = new Array({title:"The Adventures of Teddy Bear", last:"Bloggs", first:"Joe", year:1996},
{title:"Journey to the West", last:"Wu", first:"Cheng'en", year:1542},
{title:"The Adventures of Teddy Bear", last:"Bloggs", first:"Fred", year:2012});
books.sortOn(["title", "last", "first", "year"],
[Array.CASEINSENSITIVE | Array.DESCENDING, Array.CASEINSENSITIVE,
Array.CASEINSENSITIVE, Array.NUMERIC | Array.DESCENDING]);
for(var i:String in books){
trace(books[i].title + " by " + books[i].first + " "
+ books[i].last + " published in " + books[i].year);
}
|
|
看起來很複雜!讓我們逐一分解。
- 首先,我們使用三個物件字面量建立了一個新的陣列。每個物件都有一個標題、一個姓氏、一個名字和一個年份。請注意,此處每個物件都是一個關聯陣列。
- 接下來,我們使用 sortOn。sortOn 的第一個引數是一個數組,該陣列包含用作排序鍵的屬性名稱。第 0 個元素 title 是主要排序鍵,第 1 個元素 last 是次要排序鍵,依此類推。
- 第二個引數是一個數組,該陣列包含用於每個排序的陣列常量。在本例中,我們希望對字串欄位使用 Array.CASEINSENSITIVE,對出版年份使用 Array.NUMERIC,對作者和出版年份使用 Array.DESCENDING。還使用了按位 OR 運算子。
- 最後,我們從第 0 個元素到第 2 個元素跟蹤了新的陣列。
分解之後,它並不難,對吧?我們也可以使用它對 MovieClips 和其他類的例項進行排序。這種看似無用的技術在您需要呈現大量元素時非常有用。例如,如果您要製作一個帶有關卡編輯器的遊戲,則需要一種方法來顯示關卡。玩家可以按出版日期、評分、難度等對關卡進行排序。
reverse() 是反轉陣列的簡便快捷方法。
| 程式碼 | 結果 |
|---|---|
var myArray:Array = [1, 300, -Infinity, 2, 4, 4.3e-3, Infinity, -3, 6, 0x2A];
myArray.sort(Array.NUMERIC | Array.DESCENDING);
trace(myArray);
myArray.reverse();
trace(myArray);
|
|
我們已經完成了第二部分中的兩章,到目前為止,我們只是在處理資料,而沒有在螢幕上進行任何實際的輸出。這可能讓您不太滿意,因此讓我們繼續討論 Flash 應用程式的核心:MovieClip。