[flexcoders] Converting strings to numbers before sorting?

2009-02-26 Thread Keith Hughitt
Hi all,

I have a problem related to sorting type-casted numeric data, and was
wondering if someone could help me out:

Given some numeric data stored as strings (11.5), how can I populate
it into a DataGrid and have it sort properly?

From the Flex API docs
http://livedocs.adobe.com/flex/3/langref/mx/controls/dataGridClasses/Da\
taGridColumn.html#sortCompareFunction  it appears that when you use a
labelFunction instead of a dataField to specify what should be displayed
in a column, that the output of the label function is what is then used
for sorting:

If you specify a value of the labelFunction property,   you must
also provide a function to the sortCompareFunction property,  
unless sorting is not allowed on this column.

So my first attempt was to simply cast the strings to numbers within the
label function and hope that the default sorters would still be
available:

private function testLabel2(item:Object, col:DataGridColumn):Number {
 return parseFloat(item.string);
}
... I also tried using Number(item.string), however, neither worked so
I went to manually specifying the sort compare function:

 public function sortAsIs(obj1:Object, obj2:Object):int {
 if (obj1  obj2)
 return -1;
 else if (obj1 == obj2)
 return 0;
 else
 return 1;
 }

This didn't do the trick either. So finally, I decided to try doing the
conversion in the sortCompareFunction, just in case it was comparing the
original data fields and not the output of the label function. Again no
luck.

Anyone have any suggestions? Any help would be greatly appreciated.

Here is the full code for the test case I am describing:

?xml version=1.0 encoding=utf-8?
mx:Application xmlns:mx=http://www.adobe.com/2006/mxml;
 mx:Script
 ![CDATA[
 import mx.collections.ArrayCollection;

 [Bindable]
 public var test:ArrayCollection = new ArrayCollection([
 {string: 11.0, number: 11.0},
 {string: 0, number: 0},
 {string: 7.75, number: 7.75},
 {string: 8, number: 8},
 {string: 3, number: 3},
 {string: 8.93, number: 8.93}
 ]);

 private function testLabel1(item:Object,
col:DataGridColumn):Number {
 return Number(item.string);
 }

 private function testLabel2(item:Object,
col:DataGridColumn):Number {
 return parseFloat(item.string);
 }

 public function sortAsIs(obj1:Object, obj2:Object):int {
 if (obj1  obj2)
 return -1;
 else if (obj1 == obj2)
 return 0;
 else
 return 1;
 }

 public function sortAfterCasting(obj1:Object, obj2:Object):int {
 var a:Number = Number(obj1);
 var b:Number = Number(obj2);

 if (a  b)
 return -1;
 else if (a == b)
 return 0;
 else
 return 1;
 }

 ]]
 /mx:Script

 mx:DataGrid id=testDG dataProvider={test}
 mx:columns
 mx:DataGridColumn dataField=string /
 mx:DataGridColumn dataField=number /
 mx:DataGridColumn headerText=Number(string) - sortAsIs
labelFunction=testLabel1 sortCompareFunction=sortAsIs/
 mx:DataGridColumn headerText=parseFloat(string) -
sortAsIs labelFunction=testLabel2 sortCompareFunction=sortAsIs/
 mx:DataGridColumn headerText=Number(string) - casting
labelFunction=testLabel1 sortCompareFunction=sortAfterCasting/
 mx:DataGridColumn headerText=parseFloat(string) - casting
labelFunction=testLabel2 sortCompareFunction=sortAfterCasting/
 /mx:columns
 /mx:DataGrid
/mx:Application


Thanks!
Keith




Re: [flexcoders] Converting strings to numbers before sorting?

2009-02-26 Thread Adrian Williams

Hi Keith,

   Have you tried casting your string to a number via the number() 
function first? Number() handles floating points well.  We have the same 
problem sorting kit numbers in true numerical fashion as we can have 
some that begin with a letter versus a true number.  So in our sort 
compare we do this:


   public static function compareKitNumbers(obj1:Object, 
obj2:Object):int

   {
   var value1:Number = (obj1.KitNum == '' || obj1.KitNum == 
null) ? null : new Number(obj1.KitNum);
   var value2:Number = (obj2.KitNum == '' || obj2.KitNum == 
null) ? null : new Number(obj2.KitNum);

   var kitnum1:String = obj1.KitNum as String;
   var kitnum2:String = obj2.KitNum as String;
   var kit1Length:int = kitnum1.length - 1;
   var kit2Length:int = kitnum2.length - 1;
  
   if (isNaN(value1)  isNaN(value2))

   {
   if (kitnum1.substr(0,1)  kitnum2.substr(0,1))
   {
   return -1;
   }
   else if (kitnum1.substr(0,1)  kitnum2.substr(0,1))
   {
   return 1;
   }
   else
   {
   value1 = new Number(kitnum1.substr(1,kit1Length));
   value2 = new Number(kitnum2.substr(1,kit2Length));
   }
   }

   if (value1  value2 || (isNaN(value2)  !isNaN(value1)))
   {
   return -1;
   }
   else if (value1  value2 || (isNaN(value1)  !isNaN(value2)))
   {
   return 1;
   }
   else
   {
   return 0;
   }
   }

HTH,
Adrian


Keith Hughitt wrote:


Hi all,

I have a problem related to sorting type-casted numeric data, and was 
wondering if someone could help me out:


Given some numeric data stored as strings (11.5), how can I populate 
it into a DataGrid and have it sort properly?


From the Flex API docs 
http://livedocs.adobe.com/flex/3/langref/mx/controls/dataGridClasses/DataGridColumn.html#sortCompareFunction 
it appears that when you use a labelFunction instead of a dataField to 
specify what should be displayed in a column, that the output of the 
label function is what is then used for sorting:


If you specify a value of the |labelFunction| property, you must
also provide a function to the |sortCompareFunction| property,
unless sorting is not allowed on this column. 

So my first attempt was to simply cast the strings to numbers within 
the label function and hope that the default sorters would still be 
available:


private function testLabel2(item:Object, col:DataGridColumn):Number {
return parseFloat(item.string);
}

... I also tried using Number(item.string), however, neither worked 
so I went to manually specifying the sort compare function:


public function sortAsIs(obj1:Object, obj2:Object):int {
if (obj1  obj2)
return -1;
else if (obj1 == obj2)
return 0;
else
return 1;
}

This didn't do the trick either. So finally, I decided to try doing 
the conversion in the sortCompareFunction, just in case it was 
comparing the original data fields and not the output of the label 
function. Again no luck.


Anyone have any suggestions? Any help would be greatly appreciated.

Here is the full code for the test case I am describing:

?xml version=1.0 encoding=utf-8?
mx:Application xmlns:mx=http://www.adobe.com/2006/mxml;
mx:Script
![CDATA[
import mx.collections.ArrayCollection;
   
[Bindable]

public var test:ArrayCollection = new ArrayCollection([
{string: 11.0, number: 11.0},
{string: 0, number: 0},
{string: 7.75, number: 7.75},
{string: 8, number: 8},
{string: 3, number: 3},
{string: 8.93, number: 8.93}
]);
   
private function testLabel1(item:Object, 
col:DataGridColumn):Number {

return Number(item.string);
}
   
private function testLabel2(item:Object, 
col:DataGridColumn):Number {

return parseFloat(item.string);
}
   
public function sortAsIs(obj1:Object, obj2:Object):int {

if (obj1  obj2)
return -1;
else if (obj1 == obj2)
return 0;
else
return 1;
}
   
public function sortAfterCasting(obj1:Object, obj2:Object):int {

var a:Number = Number(obj1);
var b:Number = Number(obj2);
   
if (a  b)

return -1;
else if (a == b)
return 0;
else
return 1;
}

]]
/mx:Script
   
mx:DataGrid id=testDG dataProvider={test}

mx:columns
mx:DataGridColumn dataField=string /
mx:DataGridColumn dataField=number /