# Recipe 6.11 Implementing a Custom Sort

#### 6.11.1 Problem

You want to sort an array in a way such that the basic sort( ) and sortOn( ) methods do not suffice. You want to sort an array in a case-insensitive manner, perform a numeric sort, or use another custom or multikey criterion.

#### 6.11.2 Solution

Use the sort( ) method and pass it a reference to a compare function.

#### 6.11.3 Discussion

If you want complete control over sorting criteria, use the sort( ) method with a custom compare function (also called a sorter function). The compare function is called repeatedly by the sort( ) method to reorder two elements of the array at a time. The compare function receives two parameters (let's call them a and b), which it should compare to determine which one should be ordered first. Your custom compare function should return a positive number, a negative number, or 0, depending on how the elements are to be sorted. If the function returns a negative number, a is ordered before b. If the function returns 0, then the current order is preserved. If the function returns a positive number, a is ordered after b. Your compare function is called with every relevant combination of elements until the entire array has been properly ordered. Using a custom compare function is easier than it sounds. You do not need to concern yourself with the details of the sorting algorithm; you simply specify the criteria for comparing any two elements.

Here is a simple compare function that performs a case-insensitive sort:

```function insensitiveSorter(a, b) {
itemOne = a.toUpperCase(  );
itemTwo = b.toUpperCase(  );
if (itemOne > itemTwo) {
return 1;
} else if (itemOne < itemTwo) {
return -1;
} else {
return 0
}
}```

Case-insensitive sorting is useful when you have an array of values with mixed cases, because Flash automatically sorts all uppercase letters before lowercase letters by default:

```myArray = ["cardinal", "California", "camel", "Chicago"];
myArray.sort(  );
trace(myArray);  // Displays: California,Chicago,camel,cardinal```

However, when you use the case-insensitive sort utilizing the custom sorter function as defined previously, Flash sorts the values in alphabetical order regardless of case:

```myArray = ["cardinal", "California", "camel", "Chicago"];
myArray.sort(insensitiveSorter);
trace(myArray);  // Displays: California,camel,cardinal,Chicago```

When sorting numbers, the standard sort( ) method produces unexpected results. Numbers are sorted "alphabetically" instead of numerically. After the following example, myArray is [1,12,2,3,4,43], not [1,2,3,4,12,43]:

```myArray = [1, 12, 2, 3, 43, 4];
myArray.sort(  )
trace (myArray);  // Displays: 1,12,2,3,4,43 not 1,2,3,4,12,43```

Here is a simple compare function that performs a numeric sort, instead of a string-based sort, even if the elements are strings, such as "1", "2", "3":

```function numberSorter(a, b) {
itemOne = parseInt(a);
itemTwo = parseInt(b);
if (itemOne > itemTwo) {
return 1;
} else if (itemOne < itemTwo) {
return -1;
} else {
return 0
}
}```

You can use it as follows:

```myArray = [1, 12, 2, 3, 43, 4];
myArray.sort(numberSorter);
trace (myArray);  // Displays: 1,2,3,4,12,43```

In the numberSorter( ) function, the difference between the two numbers yields a positive result if a is greater than b, and a negative result if the opposite is true. It yields 0 if they are equal. Therefore, numeric comparisons of the previous type can be simplified as follows.

```function numberSorter(a, b) {
itemOne = parseInt(a);
itemTwo = parseInt(b);
return (itemOne - itemTwo);
}```

You can easily modify the sort function to sort the numbers in reverse order, as follows:

```function reverseSorter(a, b) {
itemOne = parseInt(a);
itemTwo = parseInt(b);
return (itemTwo - itemOne);
}```

Here is a full-fledged example that sorts the cars array by make and year:

```// Create an array with elements that have some matching make properties but
// different year and color properties.
cars = new Array(  );
cars.push({make: "Honda",    year: 1997, color: "maroon"});
cars.push({make: "Chrysler", year: 2000, color: "beige"});
cars.push({make: "Mercedes", year: 1985, color: "blue"});
cars.push({make: "Fiat",     year: 1983, color: "gray"});
cars.push({make: "Honda",    year: 1982, color: "white"});
cars.push({make: "Chrysler", year: 1999, color: "green"});
cars.push({make: "Mercedes", year: 2002, color: "tan"});
cars.push({make: "Fiat",     year: 1981, color: "brown"});

// Create the custom compare function. The function is always passed two elements as
// parameters. It is convenient to call them a and b.
function sorter(a, b) {

// If the make property of a is larger than (meaning it comes alphabetically after)
// the make property of b, return 1 to sort a after b. If the make property of a is
// less than the make property of b, then return -1 to sort a before b. Otherwise
// (if a.make and b.make are the same), perform the comparison on the year
// property. We use String.toUpperCase(  ) to ensure a case-insensitive comparison.
// We also convert the year to an integer and use the aforementioned shortcut for
// numeric comparison.
makeOne = a.make.toUpperCase(  );
makeTwo = b.make.toUpperCase(  );
if (makeOne > makeTwo ) {
return 1;
} else if (makeOne < makeTwo) {
return -1;
} else {
return (parseInt(a.year) - parseInt(b.year))
}
}

// Call the sort(  ) method and pass it a reference to the sorter(  ) compare function.
cars.sort(sorter);

// Loop through the array and output the results.
for (var i = 0; i < cars.length; i++) {
// Displays the results alphabetically by make, then by year:
// A green 1999 Chrysler
// A beige 2000 Chrysler
// A brown 1981 Fiat
// A gray 1983 Fiat
// A white 1982 Honda
// A maroon 1997 Honda
// A blue 1985 Mercedes
// A tan 2002 Mercedes

trace("A " + cars[i].color + " " + cars[i].year + " " + cars[i].make);
}```

 Preface
 Part II: Remote Recipes
 Part III: Applications
 Appendix A. Unicode Escape Sequences for Latin 1 Characters
 Colophon