home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / CLIPPER / MISC / DYNARRAY.ZIP / TEMP.TXT
Encoding:
Text File  |  1988-08-06  |  7.0 KB  |  169 lines

  1.                      Dynamically expanding arrays in Clipper
  2.                                   By Dirk Lesko
  3.      
  4.      One problem many Clipper programers have bumped into is the need to
  5.      declare an array without knowing what the final size of the array is
  6.      going to be. Clipper does not let you dynamically increase or decrease
  7.      the number of elements in an array. This however can be circumvented
  8.      with a little bit of clever programming.
  9.      
  10.      The need to dynamically expand an array does not usually come up very
  11.      often. There are however times when it could be most useful. One
  12.      instance that comes to mind is when you want to fill an array with
  13.      field information from a database so that a menu can be displayed via
  14.      the achoice() function. This would not be a problem if you knew how many
  15.      records you were going to have in the array. If you wanted to fill the
  16.      array with only those records that matched a certain criteria however,
  17.      then you would hit the 'I can't resize the array' syndrome. This comes
  18.      up because you do not know before hand how many records are going to
  19.      meet the search criteria.
  20.      
  21.      One solution is to declare an array that is equal to the amount of
  22.      records returned by the lastrec() function. This of course works, but it
  23.      usually ends up allocating hundreds and hundreds of extra elements that
  24.      will go unused. It also proves difficult when using the len() function
  25.      to get the length of the array for doing any kind of indexing into the
  26.      array. This is where some smart programming can help.
  27.      
  28.      Let's say the example database is named CLIENTS, and it is indexed on
  29.      last name to lname.ntx. Your application needs to display a menu with
  30.      all occurences of 'SMITH' that have purchased more than $300.00 dollars
  31.      worth of material from your company, and you only want to display those
  32.      occurences where the criteria matches. One way of doing this is to use
  33.      dbedit() and SET FILTER TO (If you have a few hours to spare on every
  34.      lookup). Dbedit() also does not have source code so complex filter
  35.      conditions are virtually impossible, and not to mention. Another method
  36.      would be to use achoice() to display the list from an array, but first,
  37.      you have to get the records that match the criteria into the array.
  38.      Here's where you run into the wall. You don't know how many records are
  39.      going to match the criteria, so you don't know how many elements you
  40.      will need to declare.
  41.      
  42.      One obvious solution is to do two passes over the database, one to count
  43.      records that match the criteria, and another to load the array with each
  44.      record that matched. This approach is workable, but can be unwieldy if
  45.      you have thousands of records in your DBF file. The second solution is
  46.      to create an array and do one pass over the database file, filling
  47.      elements with matched records as you go along, and expanding the array
  48.      as you need extra elements. How you ask?, the answer is simple. The
  49.      acopy() function in extend.lib can be used to make a temporary copy of
  50.      the array holding the matched elements while you re-declare that array
  51.      to it's new size. Heres how you accomplish that feat:
  52.      
  53.           1)   use CLIENTS index LNAME
  54.           2)   seek "SMITH"
  55.  
  56.           3)   if (.not. found())
  57.                     return
  58.                endif
  59.      
  60.           4)   x = 1
  61.           5)   declare array1[x]
  62.      
  63.           6)   do while (LNAME = "SMITH")
  64.      
  65.           7)        if (SALES >= 300)
  66.      
  67.           8)             array1[x] = FNAME+LNAME+" Record #:"+str(recno())
  68.      
  69.           9)             declare array2[x]
  70.           10)            acopy(array1,array2)
  71.           11)            x = x+1
  72.           12)            declare array1[x]
  73.           13)            acopy(array1,array2)
  74.      
  75.           14)       endif
  76.      
  77.           15)       skip 1
  78.      
  79.           16)  enddo
  80.      
  81.           17)  choice = achoice(10,10,20,40,array2)
  82.           18)  goto (val(right(array2[choice],8)))
  83.      
  84.      Whats happenning here? - The code we are interested in is inside the
  85.      IF clause in the DO WHILE loop. I think you all understand the first
  86.      five lines of code so I will go right to the important stuff. Line 6
  87.      ensures that our loop ends when we are no longer on the 'SMITH' part of
  88.      our index. Line 7 verifies that the record contains the information we
  89.      are looking for. Line 8 copies the fields we want to display into
  90.      element [x] of array1. Line 9 is where the expanding starts to take
  91.      place. When a match is found, array2 is declared to contain [x] elements
  92.      and the found data is copied into array2 from array1 in line 10. Now
  93.      room must be made for an extra element in array1 so that another loop
  94.      can be done. Line 11 increments our counter by one, and in line 12,
  95.      array1 is re-declared to [x] number of elements. That gives us the extra
  96.      element we need for another loop. Line 13 copies the contents of array2
  97.      back into array1. At this point we have array2 which contains exactly
  98.      the amount of elements that have matched the criteria, and array1
  99.      contains the identical information plus an extra element to hold the
  100.      next match. Line 14 is necessary to end the IF statement properly, and
  101.      line 15 skips to the next record so that the whole process can be
  102.      repeated.
  103.      
  104.      When the DO WHILE loop hits a name other than "SMITH", it drops down to
  105.      the ENDDO statement. At this point, array2 contains the information we
  106.      were looking for, and array1 has the same information plus one extra
  107.      element that was put there 'just in case' a match was found. This array
  108.      is no longer needed and can be released.
  109.  
  110.      Array2 contains exactly the number of elements that matched the search
  111.      criteria so you can use FOR NEXT loops to index into it, and you can use
  112.      achoice(), or any other array processing functions without having to
  113.      worry about undefined elements. Notice in the example that the record
  114.      number was appended to the end of each element for viewing, and for the
  115.      GOTO after the achoice().
  116.      
  117.      This example is not intended to be a cure all for undefined elements, it
  118.      does however show how a complex problem can be solved by creative
  119.      programming. I would not recommend this approach if you are planning to
  120.      build arrays of thousands of elements, due to the memory requirements of
  121.      the acopy() function when working on very long arrays. I do recommend it
  122.      highly if you need to display subsets of your data quickly without
  123.      having to sort to complex database functions like dbedit(). I have found
  124.      the speed of this approach to be entirely acceptable, and using
  125.      achoice() instead of dbedit() usually results in faster screen displays
  126.      as well.
  127.  
  128.      End.
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147.  
  148.  
  149.  
  150.  
  151.  
  152.  
  153.  
  154.  
  155.  
  156.  
  157.  
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169.