I've got an array of dynamic strings that I need to have sorted by their lengths. ARRAY SORT does not have an intrinsic keyword for this, but it DOES have a "custom" sort capability.
So, after reading (many times over) all the info in the Help on "ARRAY SORT, USING", I created my custom sort function, and a special TYPE for passing array elements to it, etc.
Here is the result - I hope someone may find it useful.
-John
There are a lot of intertwined conditions you need to keep in mind in order to make this work. (In other words, don't expect the help file to be easy to understand...)
Since my initial results were not as expected, I went back and re-read the Help for TYPE/END TYPE, and here's what it says under "Restrictions". (The bold/italic/underline is my formatting, since this is the statement I was misunderstanding...):
The sentence I highlighted seems to contradict what the first paragraph states, but then after an hour's meditation, I understood the original meaning of the phrase "true size", and I realized: If you want to find the "actual" length, you not only need to use LEN(Item1.Txt) but be sure to use: LEN(TRIM$(Item1.Txt, ANY CHR$(0)))
Oh, and in case you're wondering why I had to create a single-member TYPE for this - "ARRAY SORT , USING" does not accomodate variable length strings...
Note the deep meaning in the wording in the help file under "Array Sort", in the section "Sorting Custom Arrays"...
In the first sentence, "may" is misleading. The later sentence that I bolded makes it clear that there is no option to use variable length strings...
OK, my NEXT step is to figure out how to use ARRAY SCAN to find the first and last of the 5-letter words.
(I'd like to avoid having to process each and every entry in a loop of code... I realize I can edit my general-purpose Function to push all the 5-letter entries to the front of the array!!! But before I could REDIM PRESERVE, I'd still need to SCAN to the first non-5-letter word.)
I'm hoping ARRAY SCAN will accept something like:
Well, I can dream, can't I?
So, after reading (many times over) all the info in the Help on "ARRAY SORT, USING", I created my custom sort function, and a special TYPE for passing array elements to it, etc.
Here is the result - I hope someone may find it useful.
-John
Code:
#BREAK ON 'only while testing #COMPILER PBCC 5 #DIM ALL #COMPILE EXE GLOBAL g_All_Words AS STRING TYPE MyItem_Type 'for use with "Array Sort USING" Txt AS STRING * 20 END TYPE FUNCTION PBMAIN() AS LONG LOCAL Words () AS MyItem_Type ' <=== won't work AS STRING LOCAL NumWords, i AS LONG, sRet AS STRING g_All_Words = TRIM$(" BUT MOUSE HAD FOOD LOVE AND WAS BANANA FOOT WHILE FRUFRU MONEY STAPLE BAGEL CEREAL HAND ") ' 4 each of: 3, 4, 5, and 6 chars long... (The actual list is 1.344Mbytes...) NumWords = PARSECOUNT(g_All_Words, $SPC) DIM Words(1 TO NumWords) PARSE g_All_Words, Words(), $SPC ARRAY SORT Words() , USING SortItemsByLength() 'put them in order by size ' FOR i = 1 TO NumWords 'show results ? STR$(i), Words(i) NEXT i MOUSE 3, DOUBLE, DOWN MOUSE ON WAITSTAT 'why doesn't this register a mouse click? Both Mouse buttons and Mouse ON need to be set beforehand... 'sRet = inkey$ 'not really needed for these abbreviated tests END FUNCTION FUNCTION SortItemsByLength(Item1 AS MyItem_Type, Item2 AS MyItem_Type) AS LONG IF LEN(TRIM$(Item1.Txt, ANY CHR$(0,20))) < LEN(TRIM$(Item2.Txt, ANY CHR$(0,20))) THEN FUNCTION = -1 : EXIT FUNCTION END IF IF LEN(TRIM$(Item1.Txt, ANY CHR$(0,20))) > LEN(TRIM$(Item2.Txt, ANY CHR$(0,20))) THEN FUNCTION = +1 : EXIT FUNCTION END IF END FUNCTION
There are a lot of intertwined conditions you need to keep in mind in order to make this work. (In other words, don't expect the help file to be easy to understand...)
Since my initial results were not as expected, I went back and re-read the Help for TYPE/END TYPE, and here's what it says under "Restrictions". (The bold/italic/underline is my formatting, since this is the statement I was misunderstanding...):
Restrictions
When measuring the size of a padded (aligned) UDT structure with the LEN or SIZEOF statements, the measured length includes any padding that was added to the structure. For example, the following UDT structure:
TYPE LengthTestType DWORD
a AS INTEGER
END TYPE
...
DIM abc AS LengthTestType
x& = LEN(abc)
Returns a length of 4 bytes in x&, since the UDT was padded with 2 additional bytes to enforce DWORD alignment. Note that the LEN and SIZEOF of individual UDT members will return the true size of the member without regard to padding or alignment. In the previous example, LEN(abc.a) returns 2.
Individual UDT structures can be up to 16 MB each. Arrays within a UDT, ASCIIZ strings and fixed-length strings may occupy the full 16 MB structure size limit.
Field strings and dynamic strings cannot be used in UDT or UNION structures. Attempting to do so results in a compile-time Error 485 ("Dynamic/Field strings not allowed").
When measuring the size of a padded (aligned) UDT structure with the LEN or SIZEOF statements, the measured length includes any padding that was added to the structure. For example, the following UDT structure:
TYPE LengthTestType DWORD
a AS INTEGER
END TYPE
...
DIM abc AS LengthTestType
x& = LEN(abc)
Returns a length of 4 bytes in x&, since the UDT was padded with 2 additional bytes to enforce DWORD alignment. Note that the LEN and SIZEOF of individual UDT members will return the true size of the member without regard to padding or alignment. In the previous example, LEN(abc.a) returns 2.
Individual UDT structures can be up to 16 MB each. Arrays within a UDT, ASCIIZ strings and fixed-length strings may occupy the full 16 MB structure size limit.
Field strings and dynamic strings cannot be used in UDT or UNION structures. Attempting to do so results in a compile-time Error 485 ("Dynamic/Field strings not allowed").
Oh, and in case you're wondering why I had to create a single-member TYPE for this - "ARRAY SORT , USING" does not accomodate variable length strings...
Note the deep meaning in the wording in the help file under "Array Sort", in the section "Sorting Custom Arrays"...
A custom array may be user-defined types, fixed-length strings, or ASCIIZ strings. With a custom array sort, you can write your own simple function to tell PowerBASIC the correct sequence for any two array elements.
...
The array to be sorted, and the function parameters, must be fixed-length strings, ASCIIZ strings, or user-defined types. PowerBASIC verifies that the size of the data and parameters are identical. However, to allow maximum flexibility, it does not require that the data types be the same. Therefore, for example, it's possible to sort an array of fixed-length strings using a function with UDT parameters as long as the data size is identical. It is the programmer's responsibility to ensure accuracy.
...
The array to be sorted, and the function parameters, must be fixed-length strings, ASCIIZ strings, or user-defined types. PowerBASIC verifies that the size of the data and parameters are identical. However, to allow maximum flexibility, it does not require that the data types be the same. Therefore, for example, it's possible to sort an array of fixed-length strings using a function with UDT parameters as long as the data size is identical. It is the programmer's responsibility to ensure accuracy.
OK, my NEXT step is to figure out how to use ARRAY SCAN to find the first and last of the 5-letter words.
(I'd like to avoid having to process each and every entry in a loop of code... I realize I can edit my general-purpose Function to push all the 5-letter entries to the front of the array!!! But before I could REDIM PRESERVE, I'd still need to SCAN to the first non-5-letter word.)
I'm hoping ARRAY SCAN will accept something like:
Code:
array scan Words() , = len(5), to FirstFiver 'find the first 5-letter word
Comment