Recipe 5.3. Searching
for Matching Elements in an Array
Problem
You want
to find the first element in
an array that matches a specified value.
Solution
Use a for statement to loop through an
array and a break
statement once a match has been found. Optionally, use the
ArrayUtilities.findMatchIndex( ),
ArrayUtilities.findLastMatchIndex(
), and/or ArrayUtilities.findMatchIndices(
) methods.
Discussion
When you search for the first element in an
array that matches a specified value, you should use a for
statement, as shown in Recipe
5.2, and add a break statement to exit the loop once the
match has been found.
Using a break statement within a
for statement causes the loop to exit once it is
encountered. You should place the break statement within an
if statement so it is executed only when a certain condition
is met.
When searching for the first matching element,
the importance of the break statement is twofold. First, you
don't need to loop through the remaining elements of an array once
the match has been found; that would waste processing time. In the
following example, the break statement exits the loop after
the second iteration, saving six more needless iterations. (Imagine
the savings if there were a thousand more elements!)
Furthermore, the break statement is vital
when searching for the first match because it ensures that only the
first element is matched and that subsequent matches are ignored.
If the break statement is omitted in the following
exampleall matching elements are displayed, as opposed to the first
one only.
// Create an array with eight elements.
var letters:Array = ["a", "b", "c", "d", "a", "b", "c", "d"];
// Specify what we want to search for.
var match:String = "b";
// Use a for statement to loop through, potentially,
// all the elements of the array.
for (var i:int = 0; i < letters.length; i++) {
// Check whether the current element matches
// the search value.
if (letters[i] == match) {
// Do something with the matching element.
// In this example, display a message
// for testing purposes.
trace("Element with index " + i +
" found to match " + match);
// Include a break statement to exit the for loop
// once a match has been found.
break;
}
}
You can also search for the last matching element of an array by reversing
the order in which the for statement loops through the
array. Initialize the index variable to Array
.length -1 and loop until it reaches 0 by
decrementing the index variable, as follows.
var letters:Array = ["a", "b", "c", "d", "a", "b", "c", "d"];
var match:String = "b";
// Loop backward through the array. In this example,
// the "b" is at index 5.
for (var i:int = letters.length - 1; i >= 0; i--) {
if (letters[i] == match) {
trace("Element with index " + i +
" found to match " + match);
break;
}
}
To simplify the process of searching for
matching elements, you can use some of the static methods of the
custom ArrayUtilities class. The class is in the
ascb.util package, so the first step is to import the
class:
import ascb.util.ArrayUtilities;
The ArrayUtilities class has three
methods for finding matching elements findMatchIndex(
), findLastMatchIndex( ), and
findMatchIndices( ). The
findMatchIndex( ) method requires at least two
parameters: a reference to the array you are searching, and the
value you want to match. The method then returns either the index
of the first matching element or -1 if no matches are found; for
example:
var letters:Array = ["a", "b", "c", "d"];
trace(ArrayUtilities.findMatchIndex(letters, "b"));
// Displays: 1
trace(ArrayUtilities.findMatchIndex(letters, "r"));
// Displays: -1
You can also specify the starting index from
which the search begins. That way, you can find matches subsequent
to the first match. Specify the starting index as the third
parameter; for example:
var letters:Array = ["a", "b", "c", "d", "a", "b", "c", "d"];
trace(ArrayUtilities.findMatchIndex(letters, "a", 1));
// Displays: 4
You can tell the method to find elements that
are partial matches as well. By default, only exact matches are
found. However, if you specify a value of TRue for the
third parameter, the method finds any element containing the
substring:
var words:Array = ["bicycle", "baseball", "mat", "board"];
trace(ArrayUtilities.findMatchIndex(words, "s", true));
// Displays: 1
If you want to run a partial match and still
specify a starting index, simply pass the starting index as the
fourth parameter.
The findLastMatchIndex( ) method works identically
to findMatchIndex( ) except that
it starts looking from the end of the array.
The findMatchIndices(
) method returns an array of indices for all elements that
match the value passed in. The method requires at least two
parametersthe array and the element you want to match. For
example:
var letters:Array = ["a", "b", "c", "d", "a", "b", "c", "d"];
trace(ArrayUtilities.findMatchIndices(letters, "b"));
// Displays: 1,5
You can also run partial matches using
findMatchIndices( ). Simply
specify a Boolean value of true as the third
parameter:
var words:Array = ["bicycle", "baseball", "mat", "board"];
trace(ArrayUtilities.findMatchIndices(words, "b", true));
// Displays: 0,1,3
Each of the ArrayUtilities methods
described use the same basic techniques with a for statement. Let's
take a look at the code for the methods. The findMatchIndex( ) method is fairly
straightforward, and you can see the comments inline. One thing to
note, however, is that the method doesn't use any break statements within the for loop.
That's because it uses return
statements if a match is found. In the context of a function or
method, a return statement exits
the for statement, so the break statement is not necessary:
public static function findMatchIndex(array:Array, element:Object):int {
// Use a variable to determine the index
// from which to start. Use a default value of 0.
var startingIndex:int = 0;
// By default don't allow a partial match.
var partialMatch:Boolean = false;
// If the third parameter is a number,
// assign it to nStartingIndex.
// Otherwise, if the fourth parameter is a number,
// assign it to nStartingIndex instead.
if(typeof arguments[2] == "number") {
startingIndex = arguments[2];
}
else if(typeof arguments[3] == "number") {
startingIndex = arguments[3];
}
// If the third parameter is a Boolean value,
// assign it to partialMatch.
if(typeof arguments[2] == "boolean") {
partialMatch = arguments[2];
}
// Assume no match is found.
var match:Boolean = false;
// Loop through each of the elements of the array
// starting at the specified starting index.
for(var i:int = startingIndex;
i < array.length; i++) {
// Check to see if the element either matches
// or partially matches.
if(partialMatch) {
match = (array[i].indexOf(element) != -1);
}
else {
match = (array[i] == element);
}
// If the element matches, return the index.
if(match) {
return i;
}
}
// The following return statement is only reached
// if no match was found. In that case, return -1.
return -1;
}
The findLastMatchIndex( ) method is almost
identical to the findMatchIndex( )
method, except that it loops in reverse. The findMatchedIndices( ) method loops through the
array to find every matching index. It appends each matching index
to an array, and then it returns that array. It uses the
findMatchIndex( ) method, as shown
here:
public static function findMatchIndices(array:Array,
element:Object, partialMatch:Boolean = false):Array {
var indices:Array = new Array( );
var index:int = findMatchIndex(array,
element,
partialMatch);
while(index != -1) {
indices.push(index);
index = findMatchIndex(array,
element,
partialMatch,
index + 1);
}
return indices;
}
See Also
Recipes
5.2
and 5.10
|