11.9 General Array-Manipulation Tools
We've now seen how array methods can be used to remove elements from and add elements to arrays. ActionScript also offers built-in
methods
for
reordering
and sorting elements, converting array elements to strings, and extracting arrays from other arrays.
11.9.1 The reverse( ) Method
As its
name
suggests, the
reverse( )
method reverses the order of the elements of an array. This method is simple but impressive. Here's the syntax:
arrayName
.reverse()
And here are the results:
var x = [1, 2, 3, 4];
x.reverse();
trace(x); // Displays: "4,3,2,1"
We typically use
reverse( )
to reorder a sorted list. For example, if we have a list of products sorted by
ascending
price, we can display them from least to most expensive, or we can reverse the list to display them from most to least expensive.
Reader Exercise: Try to write your own custom function to reverse the elements in an array. Not only is it harder than it looks, you'll most likely find that the built-in
reverse( )
method is substantially faster.
11.9.2 The
sort
( ) and sortOn( ) Methods
The
sort( )
method rearranges elements in an array according to an arbitrary rule that we provide. If we provide no rule,
sort( )
places the elements in (
roughly
) alphabetical order by default. Sorting an array
alphabetically
is really easy, so let's first see how that works:
arrayName
.sort()
When we invoke an array's
sort( )
method with no arguments, its elements are temporarily converted to strings and sorted according to their Unicode code points (equivalent to ASCII values for code points below 128). For the code points of most western European languages, see Appendix B. See also Section 4.6.2.2 in Chapter 4 for important details.
// This works as expected...
var animals = ["zebra", "ape"];
animals.sort();
trace(animals); // Displays: "ape,zebra"
// Cool! What a handy little method.
// Watch out, the sort order is not strictly alphabetical...
// The capital "Z" in zebra comes before the lowercase "a" in "ape"
var animals = ["Zebra", "ape"];
animals.sort();
trace(animals); // Displays: "Zebra,ape". Oops. See Appendix B.
We can also use
sort( )
to organize array elements according to a rule of our own choosing. This technique is a little trickier to work with, but it's quite powerful. We start by creating a
compare function
that dictates how the interpreter should sort any two elements of an array. We then pass that function to the
sort( )
method when we call it, like this:
arrayName
.sort(
compareFunction
)
where
compareFunction
is the name of the function that
tells
the interpreter how to make its sorting decisions.
To build a compare function, we start with a new function that accepts two arguments (these represent any two elements in the array). In the function's body, we determine, however we see fit, which of the elements we'd like to appear earlier in the element list after a sort operation. If we want the first element to appear
before
the second element, we return a
negative
number from our function. If we want the first element to appear
after
the second element, we return a
positive
number from our function. If we want the elements to be left in the same
positions
, we return 0 from our function. In pseudocode, the approach generically looks like this:
function compareElements (element1, element2) {
if (
element1 should appear before element2
) {
return -1;
} else if (
element1 should appear after element2
) {
return 1;
} else {
return 0; // The elements should be left alone
}
}
For example, to put elements in ascending numeric order, we can use a function like this:
function sortAscendingNumbers (element1, element2) {
if (element1 < element2) {
return -1;
} else if (element1 > element2) {
return 1;
} else {
return 0; // The elements are equal
}
}
// Now that our compare function is ready, let's try it out
var x = [34, 55, 33, 1, 100];
x.sort(sortAscendingNumbers);
trace(x); // Displays: "1,33,34,55,100"
Numeric sorting functions can actually be phrased much more succinctly. The
preceding
sortAscendingNumbers( )
function can also be written as:
function sortAscendingNumbers (element1, element2) {
return element1 - element2;
}
In our optimized version, a negative number is returned if
element1
is less than
element2
, a positive number is returned if
element1
is greater than
element2
, and a 0 is returned if the two are equal. Now that's elegant! Here is a version to perform a descending sort:
function sortDescendingNumbers (element1, element2) {
return element2 - element1;
}
Example 11-6 shows a compare function that
adjusts
the default alphabetic comparison behavior of
sort( )
so that upper- and lowercase
letters
are sorted without regard to case.
Example 11-6. Case-insensitive alphabetic array sort
var animals = ["Zebra", "ape"];
function sortAscendingAlpha (element1, element2) {
return (element2.toLowerCase( ) < element1.toLowerCase());
}
animals.sort(sortAscendingAlpha);
trace(animals); // Displays: "ape,Zebra"
Of course, the comparison does not always have to involve simple strings and
numbers
. Here we sort an array of movie clips in ascending order, according to their pixel area:
var clips = [square1, square2, square3];
function sortByClipArea (clip1, clip2) {
clip1area = clip1._width * clip1._height;
clip2area = clip2._width * clip2._height
return clip1area - clip2area;
}
clips.sort(sortByClipArea);
That's a
mighty
fine sortin' machine!
Flash MX adds another useful sorting method not available in Flash 5. When the elements of an array are objects that share a specific property name, we can use
sortOn( )
to sort the objects quickly according to that property. For details, see
Array.sortOn( )
in the ActionScript Language Reference.
11.9.3 The slice( ) Method
Something of a subset of
splice( )
, the
slice( )
method retrieves a series of elements from an array. Unlike
splice( )
,
slice( )
only
retrieves
elements. It creates a new array and does not affect the array on which it is invoked. The
slice( )
method has the following syntax:
origArray
.slice(
startIndex
,
endIndex
)
where
startIndex
specifies the first element to retrieve and
endIndex
specifies the element
after
the last element we want to retrieve. The
slice( )
method returns a new array containing a copy of the series of elements from
origArray
[
startIndex
]
to
origArray
[
endIndex
-
1]
. If
endIndex
is omitted, it defaults to
origArray
.length
, and the returned array contains the elements from
origArray
[
startIndex
]
through
origArray
[
origArray
.length - 1]
. Here are a couple of examples:
var myList = ["a", "b", "c", "d", "e", "f"];
myList.slice(1, 3); // Returns ["b", "c"], not ["b", "c", "d"]
myList.slice(2); // Returns ["c", "d", "e", "f"]
11.9.4 The join( ) Method
We can use
join( )
to produce a string that represents all the numbered elements of an array. The
join( )
method starts by converting each element of the specified array to a string. Undefined elements are converted to the empty string (
""
). Then
join( )
concatenates
all the strings into one long string, separating them with a character (or series of
characters
) called a
delimiter
. Finally,
join( )
returns the resulting string. The syntax of
join( )
is:
arrayName
.join(
delimiter
)
where
delimiter
is the string used to separate the converted elements of
arrayName
. If
delimiter
is unspecified, it defaults to a comma. The result of a
join( )
statement is most easily
understood
through an example:
var siteSections = ["animation", "short films", "games"];
// Sets
siteTitle
to "animation>> short films>> games"
var siteTitle = siteSections.join(">> ");
// Sets
siteTitle
to "animation:short films:games"
var siteTitle = siteSections.join(":");
Note that
join( )
does not modify the array upon which it is invoked. Instead, it returns a string based on that array.
When called without a delimiter argument,
join( )
behaves exactly like
toString( )
. Because
toString( )
does not add a space after the comma it uses to
delimit
elements, we may wish to use
join( )
with ", " as the delimiter if we want
nicely
formatted output:
var x = [1, 2, 3];
trace(x.join(", ")); // Displays: "1, 2, 3" instead of "1,2,3"
The
join( )
method has a
potentially
surprising result when used on an array containing elements that are
themselves
arrays. Since
join( )
converts elements to strings, and arrays are converted to strings via their
toString( )
method, nested arrays are converted to strings using a comma delimiter, not the delimiter supplied as an argument to
join( )
. In other words, any delimiter supplied to
join( )
doesn't affect nested arrays. For example:
var x = [1, [2, 3, 4], 5];
x.join(""); // Returns "12,3,45" not "12345"
Reader Exercise: Write your own custom function that uses the specified delimiter to join nested arrays. Hint: Loop through all the elements of the array, checking for those that are arrays themselves. Use the
instanceof
operator (described in Chapter 5) to check whether a datum is an array. Can you create a recursive version that will work with arrays nested to an arbitrary depth?
11.9.5 The toString( ) Method
As we'll see in Chapter 12,
toString( )
is a method, common to all objects, that returns a string representation of the object upon which it is invoked. In the case of an
Array
object, the
toString( )
method returns a list of the array's elements, converted to strings and separated by commas. The
toString( )
method can be called explicitly:
arrayName
.toString()
Typically, we don't use
toString( )
explicitly; rather, it is invoked automatically whenever
arrayName
is used in a string context. For example, when we write
trace(
arrayName
)
, a list of comma-separated values appears in the Output window;
trace(
arrayName
)
is equivalent to
trace(
arrayName
.toString( ))
. The
toString( )
method is often helpful during debugging when we need a quick, unformatted look at the elements of an array. For example:
var sites = ["www.moock.org", "www.macromedia.com", "www.oreilly.com"];
// Display our array in a text field
debugOutput_txt.text = "The sites array is " + sites.toString();
trace("The sites array is " + sites.toString()); // Explicit use of toString( )
trace("The sites array is " + sites); // Implicit use of toString( )
The
join( )
method covered in the previous section offers greater formatting flexibility than
toString( )
.
|