Array类编程

样例:
ArrayMapMethod.zip
ArraySearchMethods.zip

数组是一种很重要的 数据 结 构。数组最基础的用途是存放对象的容器。数组使维护和修改相关对象变得非常简单。当你处理一系列拥有相同特性的变量时,数组的方便性就更显而易见了。比 如,你有一个列表的联系人,你可以把它们放入一个数组,这时数组就成为了一个通讯录,你可以很方便的遍历,或者提取想要的条目来进行修改。

下面的章节详细介绍了数组编程的细节。

数组类型

最常见的数组是索引数组。这个类型中,数组中的每一个元素都有一个索引值。AS3中的数组是以0为基数的;数组中第一个元素的索引是0,第二个的索引是1,以此类推。你可以通过中括号操作符 ( [ ] )来获取指定索引的元素:

// Create a new array, adding three elements to it
var arr:Array = new Array("a", "b", "c");
trace(arr); // output: a,b,c

// Overwrite the third item (at index 2) with a new string
arr[2] = "aa";
// Set the third index to a new string
arr[3] = "bb";

trace(arr); // output: a,b,aa,cc


数组中可以包含其他数组。这称作多维数组。数组可以被看作是一行,其中每个元素可以看作是一列。如果一个数组中每个元素包含一个数组,这就是一个二维数 组,可以被放入一个很多行和很多列组成的网格中。一个位图可以用一个二维数组来描述,其每个元素都是一行包含每列元素的数组。每列元素包含每个像素的色彩 信息:

// Create a new array
var arr:Array = new Array();
arr[0] = new Array("a", "b", "c");
arr[1] = new Array("d", "e", "f");
arr[2] = new Array("g", "h", "i");

trace(arr); // output: a,b,c,d,e,f,g,h,i
trace(arr[0]); // output: a,b,c
trace(arr[0][0]); // output: a
trace(arr[0][1]); // output: b
trace(arr[0][2]); // output: c
trace(arr[2][2]); // output: i        


最后一种类型的数组是关联数组,常被称作hash或map。这种数组不含索引,但相应的用键来指引元素。AS3中,关联数组的功能和一个Object类是相同的。关联数组的键值可以被看作是对象的属性。这样,你就可以用对象或数组的语法来创建关联数组:

// Create a new array
var indexedArray:Array = new Array();
// Assign index 0 to a new string
indexedArray[0] = "bob";
trace(indexedArray[0]); // output: bob
trace(indexedArray.length); // output: 1

// Create a new array
var associativeArr:Array = new Array();
// Assign a new string to key "name", making the array associative
associativeArr["name"] = "bob";
trace(associativeArr["name"]) // output: bob
trace(associativeArr.length); // output: 0 (length method unavailable to associative arrays)

var obj:Object = new Object();
obj.name = "bob";
trace(obj.name); // output: bob


注意,不管你是如何创建的关联数组,它始终是一个未排序的键值对,正因如此,它不具备索引数组的特性。一旦一个数组被赋予了键值对,这个数组就无法使用length() 方法来确定里面包含的元素个数。

修改数组内容

你可以使用中括号操作符来对指定索引赋值,你也可以用Array类的方法在数组的开始和结尾加入或删除元素。在数组末尾添加一个元素,使用push()方 法。在数组开始增加一个元素使用unshift()方法。你也可以使用 shift()和pop()方法在数组的开头和末尾删除元素。以下的例子展示了这些方法的区别:

var arr:Array = new Array();
arr.push("green");
arr.push("blue");
arr.push("violet");
trace(arr); // output: green,blue,violet

arr.unshift("yellow");
arr.unshift("orange");
arr.unshift("red");
trace(arr); // output: red,orange,yellow,green,blue,violet

// Remove the last item from the array
var lastItem:String = arr.pop();
trace(lastItem); // output: violet
// Remove the first item from the array
var firstItem:String = arr.shift();
trace(firstItem); // output: red

trace(arr); // output: orange,yellow,green,blue


你可以使用splice()方法在数组中间添加或删除元素。splice()方法的第一个参数是起始修改元素的索引:

// Create an array with two strings
var arr:Array = new Array("black", "white");

// Add two to the beginning
arr.splice(0, 0, "red", "orange", "yellow");


如果你是增加元素,第二个参数设为0,后面跟要加的元素:

// Add colors to the end
arr.splice(5, 0, "green", "blue", "violet");


如果你要删除元素,第二个参数设为要删除元素的个数:

// Remove two in the middle, starting at the third index
arr.splice(3,2);


你可以用slice()或concat()方法,以现有的数组来创建新数组。slice()方法返回一个现有数组的子集。concat()方法返回所传给它的参数的合并集。传递给这两个方法的原有数组保持不变。

// Create a combined array without changing an initial array
var initialArray:Array = new Array("red", "orange", "yellow");
// Create an array that combines the initial array with three more strings
var combinedArray:Array = initialArray.concat("green", "blue", "violet");
// Create a subset of this array without changing the original
var slicedArray:Array = combinedArray.slice(3);

trace(initialArray); // output: red,orange,yellow
trace(combinedArray); // output: red,orange,yellow,green,blue,violet
trace(slicedArray); // output: green,blue,violet          


传递数组中的元素给回调函数


数组类的方法使查询数组内元素和修改元素变得方便。这一节将详细介绍。

数组类的五个方法使用回调函数:every(), some(), forEach(), map(),和filter()。这些方法将函数当作一个参数。数组中的每个元素调用一次指定的函数。每个回调函数要有三个参数:第一个是数组中元素的指 针,第二个是该元素的索引,第三个是数组本身。

这些回调函数可以方便的在数组内所有元素上执行代码。比如,你可以用forEach()方法得到数字内所有元素:

var arr:Array = new Array(  { country:"Cameroon", continent:"Africa" },
                            { country:"Laos", continent:"Asia" },
                            { country:"Uruguay", continent:"South America" },
                            { country:"Romania", continent:"Europe" },
                            { country:"Canada", continent:"North America" } );

arr.forEach(traceContinent);


function traceContinent(element:*, index:int, arr:Array):void {

    trace(element.country + " is found in " + element.continent);
}


map()方法和forEach()相似,但它返回的是回调函数所返回的新数组。这个例子创建了一个DataProvider实例,用来格式化填充列表。 (注意你需要FLA的list组件来进行编译):

import fl.controls.Button;
import fl.controls.DataGrid;
import fl.controls.List;
import fl.data.DataProvider;

var famousWorks:Array = new Array(  { author:"Homer", work:"The Iliad" },
                                    { author:"Jules Verne", work:"Journey to the Center of the Earth" },
                                    { author:"James Joyce", work:"Ulysses" },
                                    { author:"John Steinbeck", work:"Grapes of Wrath" },
                                    { author:"Allen Ginsberg", work:"Howl" } );

// create grid to show initial array
var grid:DataGrid = new DataGrid();
grid.width = 350;
grid.height = 125;
grid.move(10, 10);
grid.dataProvider = new DataProvider(famousWorks);
addChild(grid);

// create list for formatted output
var list:List = new List();
list.width = 350;
list.move(10, 180);
list.rowCount = famousWorks.length;
addChild(list);

// create button to trigger the map method
var mapBtn:Button = new Button();
mapBtn.x = 80;
mapBtn.y = 10 + grid.height + 10;
mapBtn.width = 200;
mapBtn.label = "Format using Array.map()";
addChild(mapBtn);

mapBtn.addEventListener(MouseEvent.CLICK, onMapButtonClick);

function onMapButtonClick(evt:MouseEvent):void
{
        // generate a formmatted list using the map() method
        var formattedWorks:Array = famousWorks.map(formatFamousWork);
        var dp:DataProvider = new DataProvider(formattedWorks);
        list.dataProvider = dp;
}

function formatFamousWork(element:*, index:int, arr:Array):String {
    return element.work + " (by " + element.author + ")";
}


你可以使用filter()方法来创建另一个数组的子集。在filter()方法的回调函数中,如果数组元素需要在新数组中保留则必需返回true,反之 返回false。下面的例子随机产生100个0-100的随机数组成数组,使用filter()方法来创建大于90的数组子集:

var arr:Array = new Array();

var totalElements:uint = 100;
for(var i:uint = 0; i<totalElements; i++) {

    arr[i] = Math.round(Math.random()*100);
}

function isLargerThan90(element:*, index:int, arr:Array):Boolean {
    return element > 90;

}
var highestNumbers:Array = arr.filter(isLargerThan90);
trace(highestNumbers);


every()和some()方法要求回调函数返回一个布尔值。every()方法对数组中每个元素执行回调函数,直到回调函数返回false。相似 的,some()方法对每个元素执行回调函数直到返回true。这个动作可以用来确定数组是否达到每个标准。下面的例子确定一个数组是否都是由字符串组 成:

var arr:Array = new Array();
var totalElements:uint = 1000;

for(var i:uint = 0; i<totalElements; i++) {
    arr[i] = "name";
}

trace("Array is entirely composed of strings: " + arr.every(hasOnlyStrings));

function hasOnlyStrings(element:*, index:int, arr:Array):Boolean {
    return element is String;
}

arr[42] = 81; // change one element to a number

trace("Array is entirely composed of strings: " + arr.every(hasOnlyStrings));


数组中搜索元素

你可以用indexOf()或lastIndexOf()方法寻找数组中的元素。这些方法使用优化的搜索方法,比自定义的搜索循环有更好的表现。下面的例子比较用indexOf()方法搜索、循环搜索和for each搜索:

// assumes having two components on the screen:
// 1. A TextArea named outputTxt
// 2. A Button named startBtn

var loopCount:Number = Math.pow(10,6);
var loopingTally:uint = 0;
var forEachTally:uint = 0;
var indexOfTally:uint = 0;
var testsToMake:uint = 5;

// Create a large array composed entirely of zeroes
var a:Array = new Array();

for (var i:uint=0; i<loopCount; i++)
{
    a[i] = 0;
}

// Start a timer that will start a new test every half-second, up to the total tests needed
var t:Timer = new Timer(500,testsToMake);
// Run the makeTest function every time the timer ticks
t.addEventListener(TimerEvent.TIMER,makeTest);
// When the timer has completed, run the showResults function
t.addEventListener(TimerEvent.TIMER_COMPLETE,showResults);
t.start();

function findByLooping(toSearchFor:Number):uint {
    var start:int = getTimer();
    for (i=0; i<loopCount; i++)
    {
        if(a[i] == toSearchFor) {
            var end:int = getTimer();
            var elapsed:int = end - start;
            trace ("Found " + toSearchFor + " by looping at index: " + i + " time: " + String(elapsed));
            break;
        }
    }
    return elapsed;
}
function findByForEach(toSearchFor:Number):uint {
    var start:int = getTimer();
    for each(var entry:Number in a)
    {
        if(entry == toSearchFor) {
            var end:int = getTimer();
            var elapsed:int = end - start;
            trace ("Found " + toSearchFor + " in for each loop at time: " + String(elapsed));
            break;
        }
    }
    return elapsed;
}
function findByIndexOf(toSearchFor:Number):uint {
    var start:int = getTimer();
    var foundIndex:int = a.indexOf(toSearchFor);
    var end:int = getTimer();
    var elapsed:int = end - start;
    trace ("Found " + toSearchFor + " by indexOf() at index: " + foundIndex + " time: " + String(elapsed));
    return elapsed;
}
function makeTest(e:TimerEvent):void {
    // Get a random number
    var randomNumber:Number = Math.random();
    // Assign it to a random index in our dummy array
    a[Math.floor(Math.random()*loopCount)] = randomNumber;
    // Find it, timing various methods
    loopingTally += findByLooping(randomNumber);
    forEachTally += findByForEach(randomNumber);
    indexOfTally += findByIndexOf(randomNumber);   
}
function showResults(e:TimerEvent):void {
    trace("== Average search time by looping: " + loopingTally/testsToMake);
    trace("== Average search time by for each: " + forEachTally/testsToMake);
    trace("== Average search time by indexOf: " + indexOfTally/testsToMake);
}


这是一些样例输出:

== Average search time by looping: 134.6
== Average search time by for each: 26
== Average search time by indexOf: 6.4


可以看出,使用indexOf()方法比另外两种方法都要快。


深入学习

关于排序数组的更多信息,请参考ActionScript 3.0 Reference的 Array 类,包含使用sort()和sortOn()方法的详细介绍。 播放列表的例子在 ActionScript 3.0 Developer's Guide中的"Working with arrays" 章节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值