DataGrid - sort a column based on its own values, and secondarily based on another columns values?

StackOverflow https://stackoverflow.com/questions/18446311

Domanda

I have an AdvancedDatagrid with two columns: Code (strings), and Value (numbers). I use the same sort function for each column. What I want to do is to sort both columns based on the Value column (numeric data), but where there is no number available, I want the sorting to be done alphabetically for the Code column.

I have simplified the problem I am facing with an example to represent what I am trying to do:

The picture shows the two columns, with the sorting of both columns based on the Value column. Where the value is NaN, I want the Code column values to be sorted Alphabetically. So the One, Two, Three, Four would remain the same, but BADC would be ABCD.

enter image description here

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
                layout="absolute" minWidth="955" minHeight="600" initialize="initializeHandler(event)">

    <mx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.events.FlexEvent;
            import mx.utils.ObjectUtil;

            [Bindable]
            private var ac:ArrayCollection;

            protected function initializeHandler(event:FlexEvent):void
            {
                ac = new ArrayCollection();

                var one:NameValueObject = new NameValueObject("One", 1);
                var two:NameValueObject = new NameValueObject("Two", 2);
                var three:NameValueObject = new NameValueObject("Three", 3);
                var four:NameValueObject = new NameValueObject("Four", 4);
                var a:NameValueObject = new NameValueObject("A", NaN);
                var b:NameValueObject = new NameValueObject("B", NaN);
                var c:NameValueObject = new NameValueObject("C", NaN);
                var d:NameValueObject = new NameValueObject("D", NaN);

                ac.addItem(one);
                ac.addItem(two);
                ac.addItem(three);
                ac.addItem(four);
                ac.addItem(b);
                ac.addItem(a);
                ac.addItem(d);
                ac.addItem(c);              
            }

            private function numericValueSort(obj1:Object, obj2:Object):int
            {
                var value1:Number = (obj1 as NameValueObject).value;
                var value2:Number = (obj2 as NameValueObject).value;

                return ObjectUtil.numericCompare(value1, value2);
            }

            private function codeLabelFunction(item:Object, column:AdvancedDataGridColumn):String
            {
                return (item as NameValueObject).code;
            }

        ]]>
    </mx:Script>

    <mx:AdvancedDataGrid width="500" height="300" dataProvider="{ac}">
        <mx:columns>
            <mx:AdvancedDataGridColumn id="codeColumn" 
                                       headerText="Code"
                                       dataField="value"
                                       labelFunction="codeLabelFunction"
                                       sortCompareFunction="numericValueSort">

            </mx:AdvancedDataGridColumn>
            <mx:AdvancedDataGridColumn id="numericValueColumn" 
                                       headerText="Value"
                                       dataField="value"
                                       sortCompareFunction="numericValueSort">

            </mx:AdvancedDataGridColumn>
        </mx:columns>
    </mx:AdvancedDataGrid>
</mx:Application>

The NaveValueObject class

package
{
    public class NameValueObject
    {
        public var code:String;
        public var value:Number;

        public function NameValueObject(aCode:String, aNumber:Number)
        {
            code = aCode;
            value = aNumber;
        }
    }
}
È stato utile?

Soluzione 3

I figured it out, and this is the sortCompareFunction I ended up using:

It checks for the 3 possible conditions of a value/s being invalid. If the only one is NaN, returns 1 or -1, otherwise does a sort based on the code column.

Then if both values are valid (not NaN), does a regualar compare:

private function numericValueSort(obj1:Object, obj2:Object):int
{
    var o1:NameValueObject = obj1 as NameValueObject;
    var o2:NameValueObject = obj2 as NameValueObject;

    if( isNaN(o1.value) && !isNaN(o2.value) ){
        return 1; // o1 appears after o2;
    }
    if( !isNaN(o1.value) && isNaN(o2.value) ){
        return -1; // o1 appears before o2
    }
    if( isNaN(o1.value) && isNaN(o2.value) ){
            // Both values are NaN, so they will have been placed 
            // at the end when compared with valid values (from previous two 
            // IF statements, but now to compare to each other, we sort using the 
            // code field
        return ObjectUtil.stringCompare(o1.code, o2.code);
    }
    // If neither value is NaN, then do a regular numeric compare
    return ObjectUtil.numericCompare(o1.value, o2.value);
}

enter image description here

Altri suggerimenti

Try this:

private function numericValueSort(obj1:Object, obj2:Object):int
{
    var o1:NameValueObject = obj1 as NameValueObject;
    var o2:NameValueObject = obj2 as NameValueObject;

    var ret:int = 0;
    if (isNaN(o1.value) || isNaN(o2.value)) {
        if (o1.code > o2.code) {
            ret = 1;
        } else if (o1.code < o2.code){
            ret = -1;
        }
    } else {
        ret = ObjectUtil.numericCompare(o1.value, o2.value);
    }
    return ret;
}

Your function process number is either are valued, also comparation is between code field of two objects

The following compare function will give priority to numeric values and sort NaN values based on the codes. The approach is to compose a new string for each object and prefix the string with a value indicating the priority (A > B):

private function numericValueSort(obj1:NameValueObject, obj2:NameValueObject):int {
  var a:String = (isNaN(obj1.value) ? "B" : "A") + obj1.value + obj1.code;
  var b:String = (isNaN(obj2.value) ? "B" : "A") + obj2.value + obj2.code;
  return ObjectUtil.stringCompare(a, b);
}

Note that this might give strange results when sorting 1, 2, 11 for instance. In that case you're better of using a natural compare. There is an ActionScript immplementation available in the AS3Commons Lang library.

I want all the NaN values to be at the bottom, irrespective of the sorting. Other than Nan values it should be sorted(keeping all the NaN values at the bottom)?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top