View Full Version : Sorting Structures on Key Value
talamar
01-18-07, 07:49 PM
Is there a way to sort a structure on key value for a loop? (would be nice to have a simple for loop here, but we can deal with only while loops)
<MvASSIGN NAME="l.keys" EXPR="{sort_keys(l.struct)}">
<MvWHILE EXPR="{l.keys}">
...do stuff here, pop off key value...
</MvWHILE>
Kent Multer
01-19-07, 10:04 AM
Hi talamar, you seem to be asking some pretty "advanced" questions on the forums. Miva Script is powerful, but it doesn't have a lot of built-in features; you sometimes end up writing a lot of code to accomplish a task that would be simple in some other languages. That's not necessarily a bad thing; simplicity has its virtues.
Here's a sorting function (two functions actually) that I've used in a few projects. It's called by a statement such as:
<MvASSIGN NAME="to" VALUE="{ Sort(from) }">
-- where "from" is an array of structures, and each structure has a member called "key." The result will be sorted by the values of the "key" members.
<MvFUNCTION NAME="Sort" PARAMETERS="from" STANDARDOUTPUTLEVEL="">
<MvASSIGN NAME="l.max" VALUE="{ miva_array_max(l.from) }">
<MvWHILE EXPR="{ l.n LT l.max }">
<MvASSIGN NAME="l.n" VALUE="{ l.n + 1 }">
<MvASSIGN NAME="l.to" VALUE="{ InsertSorted(l.to, l.from[l.n]) }">
</MvWHILE>
<MvFUNCRETURN VALUE="{ l.to }">
</MvFUNCTION>
<MvFUNCTION NAME="InsertSorted" PARAMETERS="arr, elem" STANDARDOUTPUTLEVEL="">
<MvASSIGN NAME="l.max" VALUE="{ miva_array_max(l.arr) }">
<MvIF EXPR="{ l.max EQ 0 }">
<MvASSIGN NAME="l.out[1]" VALUE="{ l.elem }">
<MvFUNCRETURN VALUE="{ l.out }">
</MvIF>
<MvWHILE EXPR="{ l.n LT max }">
<MvASSIGN NAME="l.n" VALUE="{ l.n + 1 }">
<MvIF EXPR="{ (l.elem:key LE l.arr[l.n]:key) AND (NOT l.didit) }">
<MvASSIGN NAME="l.nn" VALUE="{ l.nn + 1 }">
<MvASSIGN NAME="l.out" INDEX="{ l.nn }" VALUE="{ l.elem }">
<MvASSIGN NAME="l.didit" VALUE="1">
</MvIF>
<MvASSIGN NAME="l.nn" VALUE="{ l.nn + 1 }">
<MvASSIGN NAME="l.out" INDEX="{ l.nn }" VALUE="{ l.arr[l.n] }">
</MvWHILE>
<MvIF EXPR="{ NOT l.didit }">
<MvASSIGN NAME="l.nn" VALUE="{ l.nn + 1 }">
<MvASSIGN NAME="l.out" INDEX="{ l.nn }" VALUE="{ l.elem }">
</MvIF>
<MvFUNCRETURN VALUE="{ l.out }">
</MvFUNCTION>
Kinda clumsy compared to PHP, but it gets the job done :^) . And of course, in many cases, database indexes can be used instead of manual sorts. I've written thousands of pages of Miva code, and I've only needed those sorting functions a couple of times. I think Miva Script has enough built-in features and shortcuts to be pretty comfortable to work with. Newer versions have additonal features for encryption, file access, etc. that aren't mentioned in the manuals, so if you're doing any heavy-duty apps, make sure you download all the release notes and check the New Features lists.
Have Fun! --
mvmarkus
01-19-07, 11:35 AM
Is there a way to sort a structure on key value for a loop? (would be nice to have a simple for loop here, but we can deal with only while loops)
<MvASSIGN NAME="l.keys" EXPR="{sort_keys(l.struct)}">
<MvWHILE EXPR="{l.keys}">
...do stuff here, pop off key value...
</MvWHILE>
The easiest way is to turn the structure into an array and then loop through it. You can profit from the fact that structures are stored in alphabetic order of the key values. All you need to do is:
<MvASSIGN NAME = "l.array" VALUE = "{ miva_array_deserialize( trim( l.structure)) }" >
<MvWHILE EXPR="{l.array[l.a]}">
...do stuff here, pop off key value...
</MvWHILE>[/QUOTE]
The trim() turns the structure into a string, which is then turned into an array by the miva_array_deserialize(). Each member of the structure becomes then a member/dimension of the new array, which dimensions are sorted in the alphabetic order of the former key values.
This probably won't work for structures of structures; there you may need to do the same for each member.
The advantage of this way is that you don't need any reflection mechanism to find out all the individual member names. Mivascript doesn't offer any reflection of structures, so you'd need to run through an ugly miva_array_serialized() and then parse the string. A horribly inefficient way.
Markus
vBulletin® v3.7.4, Copyright ©2000-2009, Jelsoft Enterprises Ltd.