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

    tricky array sort

    Level 7
      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
          kglad Adobe Community Professional & MVP
          create a custom sort function to use with the array sort() method.
          • 2. Re: tricky array sort
            Level 7
            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
              Level 7
              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."
              >