Sometimes in life you just need data to be sorted. Whether its a case insensitive sort (for names) or a numeric sort (for, uh, numbers), you just want things sorted in a particular order.

This example demonstrates how you can take a bunch of random numbers in an ArrayCollection and sort them numerically in ascending order.

Download source (ZIP, 1K) | View MXML

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" verticalAlign="middle" backgroundColor="white" creationComplete="init()">
 
    <mx:Script>
        <![CDATA[
            import mx.collections.SortField;
            import mx.collections.Sort;
            import mx.collections.ArrayCollection;
 
            [Bindable]
            private var arrColl:ArrayCollection;
 
            /** This method gets called by the main mx:Application tag and initializes/populates the ArrayCollection object with a bunch of random numbers. */
            private function init():void {
                var i:int;
 
                /* Initialize and populate the ArrayCollection object. */
                arrColl = new ArrayCollection();
                for (i = 0; i < 20; i++) {
                    arrColl.addItem({data:getRandomNumber().toFixed(4)});
                }
            }
 
            /** This method returns a random floating-point number between 0 and 10000. */
            private function getRandomNumber():Number {
                return Math.random() * 10000;
            }
 
            /** This method gets called by the Button control's click handler and creates a new SortField and Sort object which are used to sort the ArrayCollection. */
            private function button_click():void {
                /* Create the SortField object for the "data" field in the ArrayCollection object, and make sure we do a numeric sort. */
                var dataSortField:SortField = new SortField();
                dataSortField.name = "data";
                dataSortField.numeric = true;
 
                /* Create the Sort object and add the SortField object created earlier to the array of fields to sort on. */
                var numericDataSort:Sort = new Sort();
                numericDataSort.fields = [dataSortField];
 
                /* Set the ArrayCollection object's sort property to our custom sort, and refresh the ArrayCollection. */
                arrColl.sort = numericDataSort;
                arrColl.refresh();
            }
        ]]>
    </mx:Script>
 
    <mx:List id="list" dataProvider="{arrColl}" textAlign="right" labelField="data" width="100" />
 
    <mx:Button id="button" label="sort items" click="button_click()" />
 
</mx:Application>

View source is enabled in the following example.

 
Tagged with:
 
About The Author

Peter deHaan

Peter deHaan currently works for Adobe on the Flex SDK QA team. While not working on Flex, Flash, and ColdFusion applications, Peter enjoys making up bios and writing in 3rd person. Peter's rarely updated blog can be found at blogs.adobe.com/pdehaan/, actionscriptexamples.com, airexamples.com, and coldfusionexamples.com.

38 Responses to Sorting an ArrayCollection using the SortField and Sort classes

  1. andrei says:

    Thanks for the tip. Really useful. It would be also useful to know that to sort descending you need to add “dataSortField.descending = true;”

    Have phun,
    Andrei

  2. peter says:

    If an ArrayCollection contains a number of Foo objects and Foo has an attribute an instance of the class Bar and Bar has an attribute of fizz, can a SortField be used to sort Foo’s by the fizz attribute? I’ve tried doing new SortField(‘bar.fizz’) but get a runtime error stating that bar.fizz isn’t a property of Foo — even though it is. Is there any way around this?

  3. valentineday says:

    There is great!

    Hey Peterd, if I want to sort by text what code should I replace for below?

    dataSortField.numeric = true;

    Thanks

  4. peterd says:

    valentineday,

    I haven’t tested it, but you could either try passing “false”, or perhaps just comment out/delete that line altogether.

    Also, if you want to do a non-case-sensitive text search, you may want to try setting the caseInsensitive property to true.

    Peter

  5. bader says:

    Hi,
    I’m looking for the same answer for as Peter stated [is there a one..?];

    peter Oct 3rd, 2007 at 12:51 pm
    If an ArrayCollection contains a number of Foo objects and Foo has an attribute an instance of the class Bar and Bar has an attribute of fizz, can a SortField be used to sort Foo’s by the fizz attribute? I’ve tried doing new SortField(’bar.fizz’) but get a runtime error stating that bar.fizz isn’t a property of Foo — even though it is. Is there any way around this?

    thanks,
    -bader

  6. Jason says:

    Hi,
    I to, am looking for a solution to the same problem as bader & peter
    (If an ArrayCollection contains a number of Foo objects and Foo has an attribute an instance of the class Bar and Bar has an attribute of fizz, can a SortField be used to sort Foo’s by the fizz attribute? I’ve tried doing new SortField(’bar.fizz’) but get a runtime error stating that bar.fizz isn’t a property of Foo — even though it is. Is there any way around this?)

    You see i needed to use a itemRenderer for each column in my datagrid meaning that i had to populate each column using the code “data.etc”, the problem comes into play when i want to sort a column that displays a child element of one of the objects in my arrayCollection, how do i go about doin this? Been battling for a day or two.
    thanks,
    jason

  7. vivek says:

    Hi,

    Could you please give me an example to sort numeric data in XMLListCollection? Here is my sample XML

    <group name="Esthetique" value="2997" cost="0.52">
    <group name="xx" value="652" cost="0.47">
    <group name="xyt" value="652" cost="0.54">
    <group name="sss" value="652" cost="0.23">
    <group name="ffsdfsd" value="652" cost="0.82">
    

    Thanks,
    VIvke

  8. peterd says:

    vivek,

    Here’s an example of sorting XMLListCollection using MXML and ActionScript:

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    
        <mx:Script>
            <![CDATA[
                import mx.collections.SortField;
                import mx.collections.Sort;
    
                private function sortByField(value:String,
                            isNumeric:Boolean = false,
                            isDescending:Boolean = false):Boolean {
                    var sortField:SortField = new SortField(value);
                    sortField.numeric = isNumeric;
                    sortField.descending = isDescending;
                    var sort:Sort = new Sort();
                    sort.fields = [sortField];
                    xmlListColl.sort = sort;
                    return xmlListColl.refresh();
                }
            ]]>
        </mx:Script>
    
        <mx:XMLListCollection id="xmlListColl">
            <mx:source>
                <mx:XMLList>
                    <group name="Esthetique" value="2997" cost="0.52" />
                    <group name="xx" value="652" cost="0.47" />
                    <group name="xyt" value="652" cost="0.54" />
                    <group name="sss" value="652" cost="0.23" />
                    <group name="ffsdfsd" value="652" cost="0.82" />
                </mx:XMLList>
            </mx:source>
            <mx:sort>
                <mx:Sort>
                    <mx:SortField name="@cost"
                            numeric="true"
                            descending="true" />
                </mx:Sort>
            </mx:sort>
        </mx:XMLListCollection>
    
        <mx:Panel>
            <mx:DataGrid dataProvider="{xmlListColl}" width="100%">
                <mx:columns>
                    <mx:DataGridColumn dataField="@name" />
                    <mx:DataGridColumn dataField="@cost" />
                    <mx:DataGridColumn dataField="@value" />
                </mx:columns>
            </mx:DataGrid>
            <mx:ControlBar>
                <mx:Button label="Sort by @name"
                        click="sortByField('@name')" />
                <mx:Button label="Sort by @cost"
                        click="sortByField('@cost', true, true);" />
                <mx:Button label="Sort by @value"
                        click="sortByField('@value', true, true);" />
            </mx:ControlBar>
        </mx:Panel>
    
    </mx:Application>
    

    Happy Flexing!

    Peter

  9. peterd says:

    For another example of sorting XMLListCollection, see “Sorting XML documents using an XMLListCollection”.

    Peter

  10. Paul Feakins says:

    This might be a really silly question, but how do you sort if instead of objects your array just contains strings, like this:

    [0] = “a”;
    [1] = “c”;
    [2] = “b”;

    What sort field would you use for that?!

    Paul.

  11. Thomas says:

    Paul,

    Just use the simple sort!

  12. Dan says:

    If I call sort on a list then add any new items, do i have to ‘resort’ on each insert or is it automatic now that a sort instance has been applied to the list?

  13. Peter deHaan says:

    Dan,

    I quickly tested and it appears that newly added items are automatically added into their sorted position.

    Peter

  14. Dan says:

    It doesnt seem to be sorting very well for me, I seem to have some that are unsorted; are there any known bugs with this that you know?

  15. wraevn says:

    I’m looking for the same example as peter and bader – ac.getItemAt(i).bar.fizz sorting – would love help w/ that!

    • JerryW says:

      I ran into the same issue. A fellow programmer clued me in that you can specify a compareFunction for the Sort object. In there, you can do your comparisons using your object properties. Worked like a charm.

  16. Tom says:

    How would one go about sorting by date? Do I need to create a custom comparitor? Thanks!

  17. gokcen says:

    hey very useful example thanks. I wanna know if the list constructed as sorted. I mean do we have to click sort button? Couldn’t we show the list sorted at initialization?

  18. trogger says:

    I need to loop thru my collection AFTER its sorted, but when I do I get empty data. Is there a trick to this?

  19. trogger says:

    maybe I should clarify… I have some XML data, a list of strings, say peoples names for instance. I want to sort the list, then number them, then insert a “Select All” at the top of the list (index zero). I can seem to either number them or sort them but not both. Immediately after I sort (and refresh), I try to loop through the newly sorted list but get empty values during a trace()??? This is where I would want to add in my numbering and also insert my “Select All” item.

    Any thoughts here?

  20. Anonymous says:

    is there a trick to sorting on multiple object attributes in an array list?

  21. Adobe Flex – Sorting an ArrayColleciton by Date
    /**
    * @params data:Array
    * @return dataCollection:Array
    **/
    private function orderByPeriod(data:Array):Array
    {
    var dataCollection:ArrayCollection = new ArrayCollection(data);//Convert Array to ArrayCollection to perform sort function

    var dataSortField:SortField = new SortField();
    dataSortField.name = “period”; //Assign the sort field to the field that holds the date string

    var numericDataSort:Sort = new Sort();
    numericDataSort.fields = [dataSortField];
    dataCollection.sort = numericDataSort;
    dataCollection.refresh();
    return dataCollection.toArray();
    }

  22. A few gotchas when working with ArrayCollections.

    When sorting an ArrayCollection, any further items will be auto sorted. Even if you’re adding items through the source.contact() method.

    It is best to to create a temporary copy of an ArrayCollection to be sorted. Sort it using the new Sort() object, then when done, copy back the sorted elements using .toArray(); and NOT the source.concat().

    If you are using a class level ArrayCollection that has been sorted, and you are extending the parent class that this is declared in, adding items via the child class will be auto sorted unless you have sorted the collection through a proxy temporary local collection.

    Best practice:

    MyClassLevelCollection.disableAutoUpdate();

    //creat temporary ArrayCollection for sorting.
    //Then copy them back to the class level ArrayCollection
    var tempLocalCollection:ArrayCollection = new ArrayCollection();
    tempLocalCollection.source = MyClassLevelCollection.toArray();

    var dataSortField:SortField = new SortField();
    dataSortField.name = “CountryValue”;
    dataSortField.numeric = true;
    dataSortField.descending = true;
    tempLocalCollection.sort = new Sort();
    tempLocalCollection.sort.fields = [dataSortField];
    tempLocalCollection.refresh();

    //add the newly sorted objects
    MyClassLevelCollection.source = tempLocalCollection.toArray();

    MyClassLevelCollection.enableAutoUpdate();

  23. Thanks Peter, but especially thanks to Chris.

    My issue is that I’m not able to preserve the sort for some reason. The following displays accurately, but the sort is not preserved (date descending) on subsequent calls.

                var tempAC:ArrayCollection = new ArrayCollection;
     
                tempAC.source=tasksAC.toArray();//tasksAC is my array collection I create from the db.  
     
                var dataSortField:SortField = new SortField();
                dataSortField.name = "Start";//date from sqlite
     
                dataSortField.numeric = true;
                dataSortField.descending= true;
                var numericDataSort:Sort = new Sort();
                numericDataSort.fields = [dataSortField];
     
    	        tempAC.sort=numericDataSort;
    	        tempAC.refresh();
     
    			tasksAC.source=tempAC.toArray();
    			tasksAC.enableAutoUpdate();
     
                myGColl.source = tasksAC;//dpFlat;
     
                myGrp.fields = [new GroupingField("Start")];
                myGColl.grouping = myGrp;
                myGColl.childrenField="undefined";
     
                myADG.dataProvider=myGColl;
                myGColl.refresh();
  24. Sebastian says:

    thanks for this very useful tip. It helps me, to sort my datagrid which is based on an array collection

  25. Dhaya says:

    Hi, i’m actually sorting directly on the Array source of the ArrayCollection, which you’ll see is done using just two lines of code, instead of instianciating Sort / SortField classes. It works for me, i don’t know how much it’ll impact the performances of bigger apps, but hey… that’s a nice workaround at least :)


    var myAC:ArrayCollection = new ArrayCollection();

    for ( var i:int = 0; i < 10; i++ ) {
    myAC.addItem( { data: int(Math.random() * 200) } );
    }

    myAC.source.sortOn('data', Array.NUMERIC);
    myAC.refresh();

  26. joel says:

    thanks for this post…although I could have figured this out in a reasonable amount of time, your post allowed me to achieve my implementation much faster.

  27. Nirmal Kumar Bhogadi says:

    Hi,

    Is there any way to sort currency values. I have a datagrid column where I show currency values. I get the data in $35.87 format. Can someone help me how to sort these values.

    Thanks,
    Nirmal Kumar Bhogadi

  28. Nige says:

    Much obliged, that was very useful info. Also posters for extra tips.

  29. Michelle says:

    I still have not seen anyone answer on how to sort on multiple fields such as firstName and lastName or lastName and firstName. I have tried it by creating a sortField = firstName + lastName but if errors out. I tried creating two sort Fields and sort.Fields = [firstField,lastField] and I have tried sort.Fields = [firstField+lastField].

    I have also set numeric = false

    All have failed so far.

  30. Mahesan R.V(rvmahesan@gmail.com) says:

    <![CDATA[
    import mx.collections.ArrayCollection;
    import mx.collections.Sort;
    import mx.controls.Alert;
    import mx.controls.DateField;
    import mx.utils.ObjectUtil;
    import mx.utils.object_proxy;
    [Bindable]
    private var arrClldetails:ArrayCollection = new ArrayCollection([
    {Fname:"Kranthi", Lname:"Kata", dob:"Sep 21,1978"},
    {Fname:"Vasanth", Lname:"Lola", dob:"Jun 11,1979"},
    {Fname:"Manoj", Lname:"Pati", dob:"July 12,1980"},
    {Fname:"John McClain", Lname:"Mela", dob:"Feb 12,1972"},
    {Fname:"Ross", Lname:"Geller", dob:"Jan 02,1973"},
    {Fname:"Chandler", Lname:"Bing", dob:"Oct 12,1974"},
    {Fname:"Monica", Lname:"Geller", dob:"Mar 30,1976"},
    {Fname:"Racheal", Lname:"Green", dob:"Dec 12,1977"},
    {Fname:"Feebe", Lname:"Bufae", dob:"Dec 05,1981"},
    {Fname:"Joey", Lname:"Tribiyani", dob:"Apr 12,1975"},
    {Fname:"Priya", Lname:"Katari", dob:"Mar 31,1982"}
    ]);
    private var arrData:ArrayCollection ;
    private function fnClick():void
    {

    var sortl:Sort=new Sort();
    sortl.compareFunction=fnCompareFunction;

    arrClldetails.sort=sortl;

    arrClldetails.refresh();
    // for (var i:Number=0;i< arrClldetails.length;i++)
    // mx.controls.Alert.show(arrClldetails[i].Fname);
    arrData=arr_copy(arrClldetails);

    }
    private function fnCompareFunction(ObjA:Object,ObjB:Object,fields:Array = null):int
    {
    var dateA:Date=fnDtfParceFunct(ObjA.dob,"MM/DD/YYYY");
    var dateB:Date=fnDtfParceFunct(ObjB.dob,"MM/DD/YYYY");
    return ObjectUtil.dateCompare(dateA, dateB);

    }
    public function fnDtfParceFunct(valueString:String, inputFormat:String):Date
    {
    return DateField.stringToDate(dateFormatter.format(valueString),inputFormat);
    }
    protected function button1_clickHandler(event:MouseEvent):void
    {

    var temp:ArrayCollection= arr_copy(arrClldetails);
    var ss:String="";
    for (var ii:Number=0;ii< temp.length;ii++)
    ss += temp[ii].Fname+"\n";
    mx.controls.Alert.show(ss);

    var temp1:ArrayCollection= arr_copy(arrClldetails);

    var ss1:String="";
    for(var i:Number=arrClldetails.length-1;i != -1;i–)
    {

    arrClldetails[i]= arrClldetails[Math.abs(i - (arrClldetails.length-1))];
    // ss += ""+Math.abs(i – (temp.length-1))+"\n";
    // ss1 += ""+i+"\n";
    // ss += arrClldetails[Math.abs(i - (arrClldetails.length-1))].Fname+"\n";
    // ss1 += temp[i].Fname+"\n";
    }
    // for (var ii:Number=0;ii

    //in the above code,the sort :cant modify the arrCldet //:wts the reason plz mail me

  31. Mahesan R.V(rvmahesan@gmail.com) says:

    in the prev code the sort process did not modifies the main array collection.i accessed via the second data grid it shows only the unsorted array collection.But already sorted the list and then only i accessed tht..wts the reason

  32. saiyam says:

    Hi!!
    i have 2 lists. in the first list i am randomly generating 5 numbers. after that i am moving those through drag and drop in the second list. now when i m calling sort function the first list is sorted instead of the new list..can u help me with the code..??