Sorting Arrays in Flash AS2

coolispaul
coolispaul used Ask the Experts™
on
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
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
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

Author

Commented:
Hi

Thanks,

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

Cheers

Success in ‘20 With a Profitable Pricing Strategy

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

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.

Author

Commented:
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...

Author

Commented:
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.

Author

Commented:
Yeah was just gonna mention the ordering...

Cheers
Okay, check out this beaut of a custom sort function (at the end of the code)

Here are the results. I believe this is what you were hoping for:

Table 0 : 1 : 01:05:00
Table 4 : 1 : 01:10:00
Table 5 : 47 : 08:20:00
Table 3 : 90 : 03:30:00
Table 6 : 170 : 06:20:00
Table 2 : 180 : 05:20:00
Table 1 : 190 : 01:10:00


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.sort(sortAmountTime);

// 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);
}


// okay, here's a custom sort function to first sort on amount (numerically) and then time (string)
function sortAmountTime(a, b):Number {
	var amountA:Number = parseInt(a["amount"]);
	var amountB:Number = parseInt(b["amount"]);
	// first, check on amount
	if (amountA > amountB) return 1;
	if (amountA < amountB) return -1;
	// okay, so amounts are equal, check on time
	if (a["time"] > b["time"]) return 1;
	if (a["time"] < b["time"]) return -1;
	// meh, everything is the same
	return 0;
}

Open in new window

Author

Commented:
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

Author

Commented:
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"/>

Author

Commented:
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.

Author

Commented:
Hi

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


Cheers

Author

Commented:
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

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial