Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Count Unique Keys and Occurences in Sequential File

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Count Unique Keys and Occurences in Sequential File

    Code:
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]'****************************************************************************************
    ' KEYCOUNT.BAS  (version 2, for posting).
    ' Purpose: Given a sequential input file, return the number of unique keys
    ' found and the number of occurences of each key.
    ' ------------
    ' This program consist of two separate operations:
    ' 1. Creating a test file
    ' 2. The actual mission of the software
    ' ---------
    ' Input:  $DATAFILE_NAME   (input when reading the file, output when creating a new test file)
    ' Outputs: $REPORTFILE_NAME, screen info.
    ' Compilers: PB/CC v 3.03 and PB/Win 7.02
    ' Author:   Michael Mattias Tal Systems Inc Racine WI
    ' Date:     August 21 2006
    ' Use/Redistribuotion: Code placed in public domain by author 8/21/06
    ' Other software required: None.
    ' ===[ GENERAL NOTES]
    ' Original discussion at  [URL="http://www.powerbasic.com/support/pbforums/../forums/Forum6/HTML/005601.html"]http://www.powerbasic.com/support/forums/Forum6/HTML/005601.html[/URL] 
    ' "Plan A" used the PowerTree method posited by the author in the above post,
    '  but for the 2,000,000 record file with 10,000 unique keys the program took more than
    ' five (5) hours to run.
    ' This is "Plan B"  which took about two and one-half minutes to run against the same file.
    ' ****************************************************************************************[/SIZE][/FONT][/SIZE][/FONT][FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]#COMPILE      EXE
    #REGISTER     NONE
    #DEBUG        ERROR ON
    #DIM          ALL
    #TOOLS        OFF           '<<< need for TRACE, PROFILE, CALLSTK etc
                                ' Note that this program is set up for a PROFILE.[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]#INCLUDE "Win32API.INC"     ' version used: May 9 2002
    #IF NOT %DEF (%INVALID_HANDLE_VALUE_LONG)
        %INVALID_HANDLE_VALUE_LONG    = -1&
    #ENDIF[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]#IF %DEF(%PB_CC32)          ' make MSGBOX a standard function[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3] FUNCTION MSGBOX (szText AS ASCIIZ, OPTIONAL BYVAL Style AS DWORD, OPTIONAL szCaption AS ASCIIZ) AS LONG[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    LOCAL uType AS LONG, dwCap AS DWORD[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    uType = IIF& (Style=%NULL,%MB_OK OR %MB_TASKMODAL, Style)[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    dwCap =   VARPTR(szCaption)  ' if null, Windows uses "Error"[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    FUNCTION = MessageBox (BYVAL %NULL, szText, BYVAL dwCap, BYVAL uType)[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]  END FUNCTION
    #ELSE                ' make STDOUT a standard function
       FUNCTION STDOUT (Z AS STRING) AS LONG
     ' returns TRUE (non-zero) on success[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]   LOCAL hStdOut AS LONG, nCharsWritten AS LONG
       LOCAL w AS STRING
       STATIC CSInitialized AS LONG, CS AS CRITICAL_SECTION[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]   IF ISFALSE CSInitialized THEN
           InitializeCriticalSection CS
           CSInitialized  =  1
       END IF[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]   EntercriticalSection Cs[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]   hStdOut         = GetStdHandle (%STD_OUTPUT_HANDLE)
       SELECT CASE AS LONG hStdOut
           CASE %NULL, -1&
               AllocConsole
               hStdOut       = GetStdHandle (%STD_OUTPUT_HANDLE)
       END SELECT[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]   LeaveCriticalSection    CS
       w                     = Z & $CRLF
       FUNCTION              = WriteFile(hStdOut, BYVAL STRPTR(W), LEN(W),  nCharsWritten, BYVAL %NULL)[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]
     END FUNCTION[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]
    #ENDIF   ' if %DEF (%Pb_CC32)[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]' -----------------------
    ' PROGRAM CONSTANTS
    ' -----------------------
    ' For creation of test file.
    ' since we want to make sure our testing can confirm our code, we will create
    ' the test file such that each unique key appears exactly the same number of times.
    ' They will appear in random order, so the test IS fair.[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]' 10,000 keys x 200 repeats =   2,000,000 records.
    ' 2,000, 000 records takes about 5 hours with PT method.
    %NUM_UNIQUE_KEYS   = 10000&
    %NUM_KEY_REPEATS   = 200&       ' number of times each unique key will repeat
    '  The total number of records in the generated test file will equal
    '  %NUM_UNIQUE_KEYS * %NUM_KEY_REPEATS[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]' for both creation of test file and doing the processing (only MAX is used for reading)
    %KEY_LENGTH_MIN        =   8
    %KEY_LENGTH_MAX        =  16
    ' to create varible-length keys
    %RNG_SEED_KEYLEN       = 123 '  just so we can repeat the test[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]' Also for creation of test file
    %RECORD_LENGTH     =  %KEY_LENGTH_MAX * 2
    ' This record length is not used when reading; that is, the read routine will accept
    ' records of any length in a production environment. We just do this so we can't make
    ' any assumptions about the data file and will have to search for the key using
    ' standard string operators.[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]' Name of file created or read
    $DATAFILE_NAME     = "D:\Testdata\Keycount\Testfile.txt"
    ' name of output file when file is read.
    $REPORTFILE_NAME   = "D:\Testdata\Keycount\Keycount_report.txt"[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]' ----------------------------------------------------------------------------------------
    ' WinMain is only a wrapper, so that when compiled with #TOOLS ON we get a PROFILE report.
    ' ----------------------------------------------------------------------------------------
    FUNCTION WINMAIN( BYVAL  hInstance   AS LONG      , _
                      BYVAL  hPrevInst   AS LONG      , _
                      BYVAL  lpszCmdLine AS ASCIIZ PTR, _
                      BYVAL  nCmdShow    AS LONG        ) AS LONG[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]' call the user function  which we can profile.[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]  STDOUT "Count Unique Keys and Occurences Demo"[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]  CALL MainProcedure ( )
      ' -------------------------------------------------------------------------------
     ' if compiled with TOOLS ON, get a PROFILE so we can see where the time was spent
       PROFILE  "keycount_profile.txt"
     ' -------------------------------------------------------------------------------[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]END FUNCTION[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]FUNCTION MainProcedure () AS LONG[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3] LOCAL nRec AS LONG
     LOCAL StartTime AS LONG, EndTime AS LONG, iMinutes AS LONG, iSeconds AS LONG
     LOCAL bCreateTestFile AS LONG
     LOCAL sPrompt AS STRING, sYn AS STRING[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3] nRec    = %NUM_UNIQUE_KEYS * %NUM_KEY_REPEATS
     sPrompt = USING$("Create new test file with #, records containing #, unique keys  Y/N? ", nRec, %NUM_UNIQUE_KEYS)[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]
     DO
     #IF %DEF(%PB_CC32)[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]     STDOUT sPrompt
         sYn = LCASE$(WAITKEY$)
     #ELSE
         sYn = LCASE$(INPUTBOX$(sPrompt, "Run Time option"))
     #ENDIF
     LOOP UNTIL  INSTR (sYn, ANY "yn")[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3] STDOUT            "CHOICE==>" & sYn
     bCreateTestfile =  (sYn = "y")[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3] IF bCreateTestFile THEN
       STDOUT "Creating new test file..."
       CALL CreateTestFile  TO nRec
       IF nRec < 0 THEN
           NRec = ABS(nRec)
           STDOUT USING$ ("Error Creating Test file  #, &", nRec, ERROR$(nRec))
           GOTO   WinMainExit
       ELSE
           STDOUT USING$("Created #, records in test file '" & $DATAFILE_NAME & "'", nRec)
       END IF
     ELSE
         STDOUT "Using existing test file"
     END IF[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]'   ------------------------------------------------------------
    '   Timing fails if this runs past midnite. Serves you right if
    '   you are still writing code at that hour.
    '   ------------------------------------------------------------
        StartTime = TIMER
        CALL        GoGetTheKeyCount_PLanB TO nRec   ' returns number of input records.
        EndTime   = TIMER
        iMinutes  =  (EndTime-StartTime) \ 60&
        iSeconds  =  (EndTime-StartTime)  MOD 60&
        STDOUT  USING$ ("Found and Reported Unique Keys in #, records in # min # seconds", nRec, iMinutes, iSeconds)[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]WinMainExit:
       MSGBOX  "All Done", %MB_ICONINFORMATION, "Demo Courtesy Michael Mattias"[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]
    END FUNCTION[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]' -----------------------------------------------------------------------
    '   Create A Test file.
    '   "by definition" for this demo the key for each each record are all
    '   characters of the input record up to but not including the first space.
    '   Returns: Number of records written to test file.
    ' -----------------------------------------------------------------------
    FUNCTION CreateTestFile () AS LONG[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    LOCAL hFile        AS LONG
        LOCAL sKey()       AS STRING
        LOCAL order ()     AS  EXT                      ' EXT is 'native' mode of RNG
        LOCAL i AS LONG, iRec  AS LONG, iPass AS LONG   ' counters
        LOCAL kl AS LONG, sB AS STRING
        LOCAL nRec  AS LONG[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    ' create an array of string keys, with character length KEY_LENGTH_MIN to KEY_LENGTH MAX
        REDIM sKey (%NUM_UNIQUE_KEYS-1)[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    ' seed the Random NumberGenerator
        RANDOMIZE  %RNG_SEED_KEYLEN
        ' build the keys array
        FOR iRec  =  LBOUND (sKey,1) TO UBOUND (sKey,1)
           ' get the random key length for this value
            kl           =  RND (%KEY_LENGTH_MIN, %KEY_LENGTH_MAX)
            sKey(iRec)   =  RSET$ (FORMAT$(iRec), kl USING "-")
        NEXT
        ' now we have an array of keys. Put all them in random order, and write
        ' to the output file
        ' make an array of random numbers, same size as above
        REDIM   order (%NUM_UNIQUE_KEYS-1)[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    ' start up the output file
        hFile = FREEFILE
        OPEN    $DATAFILE_NAME  FOR OUTPUT AS hFile
        IF ERR THEN
            STDOUT "Can't open output file '" & $DATAFILE_NAME
            FUNCTION = -1& * ERR
            EXIT FUNCTION
        END IF[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    FOR iPass =  1 TO %NUM_KEY_REPEATS
           ' randomly re-order the sKey array for each pass ...
            RANDOMIZE TIMER
            FOR i = LBOUND(order,1) TO UBOUND (order,1)
                Order(i) = RND
            NEXT iRec
            ARRAY SORT order(), TAGARRAY sKey()
            ' create file records for the array
            FOR iRec =  LBOUND(sKey,1) TO UBOUND (sKey,1)
               sb = LSET$(sKey(iRec), %RECORD_LENGTH)      ' create space-filled record
               PRINT #hFile, sb                            ' write sequential
               INCR  nRec
            NEXT iRec
        NEXT iPass[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    CLOSE hFile[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    FUNCTION = nRec[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]END FUNCTION[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]' ----------------------------------------------------------------------------------
    '  Extract the the key from the input record.
    '  FOR THIS DEMO THE KEY is all characters up to but not including the first space,
    '  space-padded to our maximum key length.
    '  Note that we put this code into a separate function for two reasons:
    '  1. It makes the code instantly reusable by changing only this function
    '  2. So it can be profiled. The total time for the count job is not just the index or work
    '     file creation and read, but the extraction of the key from the input record.
    '     Regardless of count method chosen, the extraction of the key time will be the same
    '     so this allows good 'apples for apples' comparisons.
    ' ----------------------------------------------------------------------------------[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]FUNCTION MakeKeyValue (s AS STRING) AS STRING[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3] LOCAL iPos AS LONG[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3] IPos  = INSTR(S, $SPC)  ' find first space
     IF Ipos > 1 THEN
         DECR   iPos             ' back one
         FUNCTION = LSET$(LEFT$(S,iPos), %KEY_LENGTH_MAX)
     ELSE         ' input is either 'really' null or starts with a space (logically null)
         FUNCTION = SPACE$(%KEY_LENGTH_MAX)
     END IF[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]END FUNCTION[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]' Read $DATAFILE_NAME and produce a report showing each key in the file
    ' and the count of each key.
    ' ------------------------------------------------------------------------------
    ' PLAN B. Adopted after PLAN A took way too long to execute
    ' Extract key from each record
    ' Write key to sequential work file.
    ' Load Keys to a PB String Array
    ' ARRAY SORT the keys to get all 'like' keys together
    ' Read down the arrays, counting 'same' keys and report on control breaks.
    ' ------------------------------------------------------------------------------[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]FUNCTION GoGetTheKeyCount_PLANB () AS LONG[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    LOCAL hIn AS LONG, Hout AS LONG   ' handles for input and ouput files.
        LOCAL hW  AS LONG                 ' handle to work file
        LOCAL nRead AS LONG               ' count how many records we read from input
        LOCAL nUnique    AS LONG          ' we'll count unique keys so we can compare
        LOCAL nTotalKey  AS LONG          ' for comparison against input[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    LOCAL sb AS STRING, sKey AS STRING
        LOCAL sw() AS STRING               ' array we will sort
        LOCAL lastkey AS STRING, nThisKey AS LONG, I AS LONG, iKeyNo AS LONG[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    ' for WorkFile handling
        LOCAL szWF   AS ASCIIZ * %MAX_PATH[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]
        hIn = FREEFILE
        OPEN  $DATAFILE_NAME FOR INPUT AS hIn LEN = 32768[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    hOut = FREEFILE
        OPEN   $REPORTFILE_NAME FOR OUTPUT  AS hout[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    PRINT #hOut, "Key Counter Phase (Plan B) begins at " & TIME$ & " on " & DATE$
        PRINT #hOut,
        PRINT #hOut, "Data File:" & $DATAFILE_NAME[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    STDOUT  "Beginning count at " & TIME$ & " ...."
        ' -------------------------------------------------------------------------------
        ' create a Sequential workfile containing only the keys
        ' We'll just put this in the current folder. We delete it anyway.
        ' -------------------------------------------------------------------------------
        szwF          =  "~plan.wrk"
        hW            =  FREEFILE
        OPEN             szWF FOR OUTPUT AS hW
        ' read every record of the input file
        nRead         =  0
        WHILE NOT EOF(hIn)
           LINE INPUT #hin, sB
           INCR              nRead[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]       sKey            =   MakeKeyValue (sb)  ' note this is a function so we can PROFILE it.
           ' write to workfile
           PRINT #hW, skey
        WEND[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    CLOSE hIn
        CLOSE  hW
        STDOUT USING$("Completed extraction of #, keys to workfile. Loading to array.", nRead)[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    ' create an array to hold all the keys
        REDIM sw(Nread-1)
        ' load it
        hW  =    FREEFILE
        OPEN     szwf  FOR INPUT AS hW LEN = 32768
        LINE INPUT #hW, sw()
        CLOSE    hW
        KILL    szWF   ' we're done with the work file now[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    ' Sort the keys in the array
        STDOUT           "Completed Load, start sorting arrays (" & TIME$ & ")"
        PRINT  #hOut,    "Completed Load, start sorting arrays (" & TIME$ & ")"
        ARRAY  SORT sw()
        STDOUT           "Completed SORT, start comparisons    (" & TIME$ & ")"
        PRINT #hOut,     "Completed SORT, start comparisons    (" & TIME$ & ")"[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    lastkey    = ""
        nThisKey   = 0
        nTotalKey  = 0
        FOR i = LBOUND(sw,1) TO UBOUND(sw,1)
            INCR  nTotalKey
            IF sw(i) = LastKey THEN
                INCR nThisKey
            ELSE
                IF i <> LBOUND(sw,1) THEN
                   PRINT #hOut, USING$   ("###,###     '&'  ###,###", iKeyNo, LastKey, nTHisKey)
                END IF
                LastKey  = sw(i)
                nTHisKey  = 1
                INCR nUnique
                INCR iKeyNo[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]        END IF
        NEXT
        ' report the last key..
        PRINT #hOut, USING$   ("###,###     '&'  ###,###", iKeyNo, LastKey, nTHisKey)[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]    ' finish off the report.
        PRINT# hOut,
        PRINT #hOut, USING$ ( "Records Read #,   Unique Keys Found #,  Total Keys #,", nTotalKey, nUnique, nTotalKey)
        PRINT# hout,
        PRINT #hOut, "** END OF REPORT at " & TIME$ & "  **"
        CLOSE  hOut
        ' return number of input records read.
        FUNCTION  = nRead[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]END FUNCTION  ' plan B[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][FONT=Courier New, Courier][SIZE=3]' *** END OF FILE ***[/SIZE][/FONT][/SIZE][/FONT]
    [FONT=Verdana, Arial][SIZE=2][/SIZE][/FONT]
    ------------------
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com
Working...
X