3 Replies Latest reply on Jan 28, 2009 9:59 AM by Newsgroup_User

# tricky array sort

I have an array with string values of 1,2,3,4a,5,6,4b,10,7

I would like to sort the array into 1,2,3,4a,4b,5,6,7,10

Would this be possible? I can't seem to do this with the standard sorting
methods in flash.

This needs to be targeted to flash player 7.

Thanks for any pointers.

• ###### 1. Re: tricky array sort
create a custom sort function to use with the array sort() method.
• ###### 2. Re: tricky array sort
dave,

> I have an array with string values of 1,2,3,4a,5,6,4b,10,7

Okay.

> I would like to sort the array into 1,2,3,4a,4b,5,6,7,10

Aha. You'll need to sort this numerically, then, instead of the default
alphabetical. (In alphabetical, the 10 would be listed immediately after
that 1, because when considered as a word, the string "10" begins with the
same "letter" as the other string, "1".) The tricky part is, two of your
entries -- 4a and 4b -- are strings.

> Would this be possible? I can't seem to do this with the
> standard sorting methods in flash.

It is possible, yes. :) Let's take a quick look at two possible
approaches, targetting Flash Player 7. We'll use ActionScript 2.0.

Here's the most basic staring point:

var nums:Array = new Array(1, 2, 3, "4a", 5, 6, "4b", 10, 7);
nums.sort();
trace(nums);

... which outputs: 1,10,2,3,4a,4b,5,6,7

Notice that 4a and 4b are quoted, because they have to be, and that the
sort occurs alphabetically by default. As of Flash Player 7, AS2 allows you
to provide an optional filter to the sort() method. One of the options is a
numeric filter, accessed as a static constant of the Array class, like this:

var nums:Array = new Array(1, 2, 3, "4a", 5, 6, "4b", 10, 7);
nums.sort(Array.NUMERIC);
trace(nums);

This would work just fine if the array didn't include strings. For
example, if the 4a and 4b values were simply 4, you'd get an expected
numeric sort of 1, 2, 3, 4, 5, 6, 7, 10. So this first approach won't do in
this particular case.

Fortunately, you can also pass in an optional sorting function as a
parameter, which you can think of as a custom filter. In this case, you'll
want this custom function to perform differently depending on whether the
item under consideration is a number or a string. Assuming your values will
always adhere to the form of either a) number (x) or b)
number-followed-by-single-character (xxxy), your function might look
something like this:

var nums:Array = new Array(1, "4c", 2, 3, "4a", 5, 6, "44b", 10, 7);
nums.sort(customSort);
trace(nums);

function customSort(a:Object, b:Object):Boolean {
var x:Number = 0;
var xStr:String = "";
var y:Number = 0;
var yStr:String = "";

if (typeof a == "string") {
x = Number(a.substr(0, a.length - 1));
xStr = a.substr(a.length - 1);
}
if (typeof b == "string") {
y = Number(b.substr(0, b.length - 1));
yStr = b.substr(b.length - 1);
}

if (xStr != "" && yStr != "") {
if (x == y) {
return xStr > yStr;
} else {
return x > y;
}
} else if (xStr != "") {
return x > b;
} else if (yStr != "") {
return a > y;
}

return a > b;
};

This likely isn't the most elegant way to write the function. Partly,
I'm interested in illustrating a concept, and partly I threw this together
as quickly as I could. ;) Here's what's happening. In this case, note
that the sort() method is still being invoked on the nums array. This time,
instead of an optional filter parameter, I'm passing in a function named
customSort(). (When passed as a parameter, omit the parentheses of
functions, otherwise the function is executed as soon as it appears. In
this case, we're just passing in a *reference* to the function.)

The function receives two parameters: a and b, which are typed as
objects because the elements being compared might be strings or numbers.
This function returns a Boolean value, which determines which of the
compared elements sorts in front of the other. First, I set up a handful of
temporary variables, in case either of the incoming parametes are strings.
If a is a string, such as "4a", x wil become the numeric portion only (4),
and xStr will become the string porition ("a"). The same thing happens with
y and yStr for the b parameter.

The second block -- a pair of if() statements -- shows how that's done.
Using the typeof operator, I determine if each of the parameters is a
string. If so, the String.substr() method rips the numerals out for the
appropriate relevant variable and the character out for the other variable.
This happens for a and b.

The third block -- a series of nested if() statements -- checks of any
of the temporary string variables have content, and performs comparisons
based on the possibilites of both, either one, or neither. If both, and if
the numeric portions are the same (x == y), then the string portions are
compared with the greater than operator (xStr > yStr); otherwise, the
numeric portions are compared in the same way. If a, and only a, is a
string (that is, if xStr is not an empty string), its numeric counterpart,
x, is compared with b. The b, and only b, is a string, the reverse is
performed.

Finally, in the last line, a is simply compared with b (they're both
numbers, in this case), which provides a numeric sort.

Note that I added a new element, 4c, and changed 4b to 44b, to show that
the sort really does behave as you're expecting:

1,2,3,4a,4c,5,6,7,10,44b

David Stiller
Co-author, Foundation Flash CS4 for Designers
http://tinyurl.com/5j55cv
"Luck is the residue of good design."

• ###### 3. Re: tricky array sort
That's works well, thanks for that David.

I shall disect the code further to check I understand!

Thanks again

"David Stiller" <stiller@quip-remove-.net> wrote in message
news:glq4jf\$8dp\$1@forums.macromedia.com...
> dave,
>
>> I have an array with string values of 1,2,3,4a,5,6,4b,10,7
>
> Okay.
>
>> I would like to sort the array into 1,2,3,4a,4b,5,6,7,10
>
> Aha. You'll need to sort this numerically, then, instead of the
> default alphabetical. (In alphabetical, the 10 would be listed
> immediately after that 1, because when considered as a word, the string
> "10" begins with the same "letter" as the other string, "1".) The tricky
> part is, two of your entries -- 4a and 4b -- are strings.
>
>> Would this be possible? I can't seem to do this with the
>> standard sorting methods in flash.
>
> It is possible, yes. :) Let's take a quick look at two possible
> approaches, targetting Flash Player 7. We'll use ActionScript 2.0.
>
> Here's the most basic staring point:
>
> var nums:Array = new Array(1, 2, 3, "4a", 5, 6, "4b", 10, 7);
> nums.sort();
> trace(nums);
>
> ... which outputs: 1,10,2,3,4a,4b,5,6,7
>
> Notice that 4a and 4b are quoted, because they have to be, and that the
> sort occurs alphabetically by default. As of Flash Player 7, AS2 allows
> you to provide an optional filter to the sort() method. One of the
> options is a numeric filter, accessed as a static constant of the Array
> class, like this:
>
> var nums:Array = new Array(1, 2, 3, "4a", 5, 6, "4b", 10, 7);
> nums.sort(Array.NUMERIC);
> trace(nums);
>
> This would work just fine if the array didn't include strings. For
> example, if the 4a and 4b values were simply 4, you'd get an expected
> numeric sort of 1, 2, 3, 4, 5, 6, 7, 10. So this first approach won't do
> in this particular case.
>
> Fortunately, you can also pass in an optional sorting function as a
> parameter, which you can think of as a custom filter. In this case,
> you'll want this custom function to perform differently depending on
> whether the item under consideration is a number or a string. Assuming
> your values will always adhere to the form of either a) number (x) or b)
> number-followed-by-single-character (xxxy), your function might look
> something like this:
>
> var nums:Array = new Array(1, "4c", 2, 3, "4a", 5, 6, "44b", 10, 7);
> nums.sort(customSort);
> trace(nums);
>
> function customSort(a:Object, b:Object):Boolean {
> var x:Number = 0;
> var xStr:String = "";
> var y:Number = 0;
> var yStr:String = "";
>
> if (typeof a == "string") {
> x = Number(a.substr(0, a.length - 1));
> xStr = a.substr(a.length - 1);
> }
> if (typeof b == "string") {
> y = Number(b.substr(0, b.length - 1));
> yStr = b.substr(b.length - 1);
> }
>
> if (xStr != "" && yStr != "") {
> if (x == y) {
> return xStr > yStr;
> } else {
> return x > y;
> }
> } else if (xStr != "") {
> return x > b;
> } else if (yStr != "") {
> return a > y;
> }
>
> return a > b;
> };
>
> This likely isn't the most elegant way to write the function. Partly,
> I'm interested in illustrating a concept, and partly I threw this together
> as quickly as I could. ;) Here's what's happening. In this case, note
> that the sort() method is still being invoked on the nums array. This
> time, instead of an optional filter parameter, I'm passing in a function
> named customSort(). (When passed as a parameter, omit the parentheses of
> functions, otherwise the function is executed as soon as it appears. In
> this case, we're just passing in a *reference* to the function.)
>
> The function receives two parameters: a and b, which are typed as
> objects because the elements being compared might be strings or numbers.
> This function returns a Boolean value, which determines which of the
> compared elements sorts in front of the other. First, I set up a handful
> of temporary variables, in case either of the incoming parametes are
> strings. If a is a string, such as "4a", x wil become the numeric portion
> only (4), and xStr will become the string porition ("a"). The same thing
> happens with y and yStr for the b parameter.
>
> The second block -- a pair of if() statements -- shows how that's done.
> Using the typeof operator, I determine if each of the parameters is a
> string. If so, the String.substr() method rips the numerals out for the
> appropriate relevant variable and the character out for the other
> variable. This happens for a and b.
>
> The third block -- a series of nested if() statements -- checks of any
> of the temporary string variables have content, and performs comparisons
> based on the possibilites of both, either one, or neither. If both, and
> if the numeric portions are the same (x == y), then the string portions
> are compared with the greater than operator (xStr > yStr); otherwise, the
> numeric portions are compared in the same way. If a, and only a, is a
> string (that is, if xStr is not an empty string), its numeric counterpart,
> x, is compared with b. The b, and only b, is a string, the reverse is
> performed.
>
> Finally, in the last line, a is simply compared with b (they're both
> numbers, in this case), which provides a numeric sort.
>
> Note that I added a new element, 4c, and changed 4b to 44b, to show
> that the sort really does behave as you're expecting:
>
> 1,2,3,4a,4c,5,6,7,10,44b
>
>
> David Stiller
> Co-author, Foundation Flash CS4 for Designers
> http://tinyurl.com/5j55cv
> "Luck is the residue of good design."
>