Link to home
Start Free TrialLog in
Avatar of coolispaul
coolispaulFlag for United States of America

asked on

Sorting Arrays in Flash AS2

Hi

I have a an XML file similar to:
<root>
      <table first="Table 0" amount="1" time="01:05:00:"/>
      <table first="Table 1" amount="190" time="01:10:00"/>
      <table first="Table 2" amount="180" time="05:20:00"/>
      <table first="Table 3" amount="90" time="03:30:00"/>
      <table first="Table 4" amount="1" time="01:10:00"/>
      <table first="Table 5" amount="47" time="08:20:00"/>
      <table first="Table 6" amount="170" time="06:20:00"/>
</root>

What i want to do is pull this in to flash and sort it by amount and then time. i.e. if two amounts were the same then the time taken would be used top sort between the two. In the xml above, table 0 would come before table 4 because the time is quicker even though amount is teh same for both.

I guess i would need to create a multidimensional array from the xml but not sure how to go about this and then sort it

Any ideas?

Thanks
Avatar of tomaugerdotcom
tomaugerdotcom
Flag of Canada image

Is this the exact structure that you will be using in the final app, or is this just an abstract example and the actual XML will be a lot more complicated?
Here you go, for the data set provided. It should also work for expanded data sets - I think you should get the picture from this code.
var xmlSource:XML = new XML('<root><table first="Table 0" amount="1" time="01:05:00:"/><table first="Table 1" amount="190" time="01:10:00"/><table first="Table 2" amount="180" time="05:20:00"/><table first="Table 3" amount="90" time="03:30:00"/><table first="Table 4" amount="1" time="01:10:00"/><table first="Table 5" amount="47" time="08:20:00"/><table first="Table 6" amount="170" time="06:20:00"/></root>');
xmlSource.ignoreWhite = true; // not necessary but good practice

xmlSource = xmlSource.childNodes[0]; // drill into the <root> structure

// iterate through the XML and build up an array of objects, suitable for sortOn()
var tablesArray:Array = new Array();
// cache xmlSource.childNodes.length so we don't have to define it every time (saves processor time)
for (var i = 0, j = xmlSource.childNodes.length; i < j; ++i){
	//tablesArray.push({first:
	var xmlTable:XML = xmlSource.childNodes[i];
	// push the data from the XML into the tablesArray, as an object
	var tableFields:Object = new Object;
	// iterate through the attributes and build this object (ie: {first: ..., amount: ..., time: ...})
	
	for (var n in xmlTable.attributes){
		tableFields[n] = xmlTable.attributes[n];
	}
	// now push this into the tablesArray
	tablesArray.push(tableFields);
}

// okay, now sort on amount first, and if they are the same, sort on time
tablesArray.sortOn(["amount", "time"]);

// now to prove that it works, I'm going to iterate through the array
// and just trace out the values:
for (var i = 0, j = tablesArray.length; i < j; ++i){
	trace(tablesArray[i].first + " : " + tablesArray[i].amount + " : " + tablesArray[i].time);
}

Open in new window

Avatar of coolispaul

ASKER

Hi

Thanks,

I tried this but it doesnt seem to work. Any ideas?

Cheers

What do you mean it doesn't seem to work. It works perfectly in Flash CS3 with ActionScript 2.

You better explain a little more clearly what you mean by "doesn't work"...

Here's the output from the trace statement the script generates:

Table 0 : 1 : 01:05:00:
Table 4 : 1 : 01:10:00
Table 6 : 170 : 06:20:00
Table 2 : 180 : 05:20:00
Table 1 : 190 : 01:10:00
Table 5 : 47 : 08:20:00
Table 3 : 90 : 03:30:00
woa. you're right, that output looks fishy. hold on.
Sorry my bad - was publishing out as AS1.

Just gonna play with it but looks perfect - thanks a million

Cheers
No, it's messed - it's not sorting numerically on the amount field - it's treating it like a string. I'm working on that now...
1 problem im having is trying to read the xml from external source rather than embedded in the AS
It has no errors but outputs nothing


i.e
var xmlSource:XML
xmlSource.ignoreWhite = true;
xmlSource.onLoad = function(success){
      if (success){


xmlSource = xmlSource.childNodes[0]; // drill into the <root> structure

// iterate through the XML and build up an array of objects, suitable for sortOn()
var tablesArray:Array = new Array();
// cache xmlSource.childNodes.length so we don't have to define it every time (saves processor time)
for (var i = 0, j = xmlSource.childNodes.length; i < j; ++i){
        //tablesArray.push({first:
        var xmlTable:XML = xmlSource.childNodes[i];
        // push the data from the XML into the tablesArray, as an object
        var tableFields:Object = new Object;
        // iterate through the attributes and build this object (ie: {first: ..., amount: ..., time: ...})
       
        for (var n in xmlTable.attributes){
                tableFields[n] = xmlTable.attributes[n];
        }
        // now push this into the tablesArray
        tablesArray.push(tableFields);
}

// okay, now sort on amount first, and if they are the same, sort on time
tablesArray.sortOn(["amount", "time"]);

// now to prove that it works, I'm going to iterate through the array
// and just trace out the values:
for (var i = 0, j = tablesArray.length; i < j; ++i){
        trace(tablesArray[i].first + " : " + tablesArray[i].amount + " : " + tablesArray[i].time);
}

}else trace("Error loading XML file.");
}
tables_xml.load("tables.xml");
Okay, let's deal with the sorting issue first, then post a related question and we'll deal with the XML loading issue. I'm still working on a custom sort function for you. hold up 5 minutes. Let's close this one out first.
Yeah was just gonna mention the ordering...

Cheers
ASKER CERTIFIED SOLUTION
Avatar of tomaugerdotcom
tomaugerdotcom
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi

Yes thats pretty much perfect - its just the revese of that i.e. 190 first as it is the highest amount

Can i just do tablesArray.reverse?

Cheers
Hi

there does seem to be a bug when i am using this data below:

It seems to ignore the first row. Maybe because it has the same time as table 4?


      <table first="Table 1" amount="190" time="01:10:00"/>
      <table first="Table 2" amount="180" time="05:20:00"/>
      <table first="Table 3" amount="90" time="03:30:00"/>
      <table first="Table 4" amount="0" time="01:10:00"/>
      <table first="Table 5" amount="47" time="08:20:00"/>
      <table first="Table 6" amount="170" time="06:20:00"/>
      <table first="Table 7" amount="38" time="04:10:00"/>
      <table first="Table 8" amount="50" time="04:50:00"/>
      <table first="Table 9" amount="140" time="04:60:00"/>
      <table first="Table 10" amount="0" time="02:50:00"/>
      <table first="Table 11" amount="130" time="05:10:00"/>
      <table first="Table 12" amount="22" time="03:20:00"/>
      <table first="Table 13" amount="20" time="03:20:00"/>
      <table first="Table 14" amount="-10" time="04:30:00"/>
      <table first="Table 15" amount="80" time="07:30:00"/>
      <table first="Table 16" amount="-20" time="07:50:00"/>
      <table first="Table 17" amount="60" time="04:30:00"/>
      <table first="Table 18" amount="-100" time="05:30:00"/>
      <table first="Table 19" amount="110" time="03:40:00"/>
i fixed the reverse thing by the way - i did :
 
        if (amountA < amountB) return 1;
        if (amountA > amountB) return -1;

Cheers
Are you still putting it inside its <root> tag to start with?
This does appear to work:

var xmlString:String = '<root><table first="Table 1" amount="190" time="01:10:00"/><table first="Table 2" amount="180" time="05:20:00"/><table first="Table 3" amount="90" time="03:30:00"/><table first="Table 4" amount="0" time="01:10:00"/><table first="Table 5" amount="47" time="08:20:00"/><table first="Table 6" amount="170" time="06:20:00"/><table first="Table 7" amount="38" time="04:10:00"/><table first="Table 8" amount="50" time="04:50:00"/><table first="Table 9" amount="140" time="04:60:00"/><table first="Table 10" amount="0" time="02:50:00"/><table first="Table 11" amount="130" time="05:10:00"/><table first="Table 12" amount="22" time="03:20:00"/><table first="Table 13" amount="20" time="03:20:00"/><table first="Table 14" amount="-10" time="04:30:00"/><table first="Table 15" amount="80" time="07:30:00"/><table first="Table 16" amount="-20" time="07:50:00"/><table first="Table 17" amount="60" time="04:30:00"/><table first="Table 18" amount="-100" time="05:30:00"/>';
xmlString += '<table first="Table 19" amount="110" time="03:40:00"/></root>';

var xmlSource:XML = new XML(xmlString);

Note the <root> tag.
Hi

Yep - for some reason i am only getting 18 values though and not 19
Do you get 19 output?


Cheers
aah fixed that bit - I set var i to be -1 rather than 0 in the for loops

1 last problem is the reading xml externall rather than have it in the AS

Cheers
Okay, well, I don't feel comfortable addressing that point in this post, since this post dealt specifically with the sorting of your XML. It will be better for future users if you start a new post dealing with loading the XML into your AS.

My recommendation is, if you are happy with the resolution of your sort order question, close out this post, and then click the "Ask Related Question" link at the bottom of this post after you've closed it. That will allow you to post a new question AND will alert me to that question so you can get a quicker answer.

Best regards,

T