Announcement

Collapse
No announcement yet.

Scanning an Array for an item value = 0

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

  • Scanning an Array for an item value = 0

    I found some inconveniences with items to be scanned with Array Scan.
    (The arrays I use always start with index = 0.)
    I have to test if a certain item value is already at least once in the array.

    Dim c() As Integer
    ReDim c(10)
    c(1) = 11
    c(2) = 12
    Array Scan c(), =11, To iRet ' I'm searching for 11
    'iRet = 2 because "Array Scan" is based on 1. That's correct.

    ReDim c(10)
    c(1) = 11
    c(2) = 12
    Array Scan c(), =0, To iRet ' I'm searching for 0
    'iRet = 1 ? Why? I did not define c(0).

    ReDim c(10)
    c(5) = 11
    c(6) = 12
    Array Scan c(), =0, To iRet ' I'm searching for 0
    'iRet = 1 ? Why? I did not define c(0...4)

    ReDim c(10)
    c(0) = 0
    c(5) = 11
    c(6) = 12
    Array Scan c(), =0, To iRet
    'iRet = 1. This seems to be ok on the first sight, because iRet = 1
    'But when I assign one of the Items(0...4) with value 0, iRet is always 1.

    ReDim c(10)
    c(0) = 10
    c(5) = 0
    c(6) = 12
    Array Scan c(), =0, To iRet
    'iRet = 1. This is not ok, because iRet = 1
    'So, I cannot scan for a value = 0 which is essential to me.

    What could I do?
    Norbert Doerre

  • #2
    Code:
    ReDim c(10)
    c(1) = 11
    c(2) = 12
    Array Scan c(), =0, To iRet ' I'm searching for 0
    'iRet = 1 ? Why? I did not define c(0).

    Because (rtfm) when you DIM/REDIM an array, all elements of that array are set to zero (numerics), NULL (UDT) or the null string (STRING).

    i.e, C(0) DID equal zero and the compiler found it at the first element of the array (hit value=1)

    >What could I do?

    Let's see....

    You could under DIM/REDIM and use the subscripts option to have your array begin with subscript one.

    Or, you could under ARRAY SCAN and start the scan at subscript one of your zero-based array.

    Or, you could under FOR ..NEXT and eschew ARRAY SCAN entirely.

    (Sheesh. Every day I get more and more respect for "Support" personnel, who field rookie questions like this every day have to tell the user to - Gracefully. Me, I would have opened fire a long time ago.)

    MCM
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      I've been reading this forum for a while now and you, Mr. Mattias, seem to be one of the more helpful and engaged participants. You've helped me a time or two and I appreciate it.

      However, when you react as you did here to a meticulously asked question from someone who seems honestly confused by a situation and who couldn't have gotten this far without having read the whatever manual and demean him and his question in the way you did, is it possible you discourage others who need help from getting it here? I'm afraid I'll be more hesitant to ask after seeing this.

      Barry

      Comment


      • #4
        Oh, you shouldn't be hesitant to ask anything here at any time.

        It's only repeat offenders who get get me riled up.

        MCM
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          Michael, please, read the manual!

          Michael, thank You for Your kind answer.
          Your advice does not help because all not explicitely assigned array items with a value different from zero are also predefined with zero. So, You will never find an explicitely defined item with zero with "Array Scan", but You will also not manage with For...Next.
          Please, read the manual!
          Norbert Doerre

          Comment


          • #6
            all not explicitely assigned array items with a value different from zero are also predefined with zero.
            Could you give an example?
            Rod
            In some future era, dark matter and dark energy will only be found in Astronomy's Dark Ages.

            Comment


            • #7
              Array Scan

              Just a thought - you could store the integers as strings.

              "0","1","2", etc

              Search for the String representation - default Array Elements not used
              are NULL not "0"

              Comment


              • #8
                Help file under DIM
                Array Initialization and Absolute Arrays

                PowerBASIC generates an error message when it encounters an array that hasn't been dimensioned. If the array has already been dimensioned, the DIM statement is ignored. A new array is not created and a run-time error is not generated.
                When a program is first executed, PowerBASIC sets each element of a numeric array to zero, and sets each element of regular string arrays to a null string (length zero).[ [italics mine MCM]
                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9
                  Another solution, if the array will only contain positive integers, is to use a for:next loop to initialize the entire array to -1.

                  Barry

                  Comment


                  • #10
                    What about using string values? Fast enough?

                    Anyone else can help?
                    My problem is that I'm filling a very large dynamic array with cad entity handles. Zero is one valid handle. The array is not filled from index 0...n succeedingly. The item indices are the result of edit procedures and not predifinable. If I have to find out if a value exists more than once I have to test it before it is added to the array. As long as not all of the array items are given a value, there is always a zero present even if I did not place it into the array.
                    Is there any way to nevertheless a way to distinguish between defined zeros and predefined ones? I also cannot change the content of the array to just starting the array handle values with 1. Please consider that the existing database handling this is very, very fast. So this test for zero must be as fast, too.
                    Norbert Doerre

                    Comment


                    • #11
                      There is a lot of us trying to help. Please show code.
                      Rod
                      In some future era, dark matter and dark energy will only be found in Astronomy's Dark Ages.

                      Comment


                      • #12
                        Array Scan

                        You could always take the 0 entry out of the mix entirely -

                        Add 1 to all positive values including 0 for Array storage
                        Add 1 to the value you are trying to find in the Array
                        Subtract 1 from the Array value when you need the Value

                        If you are storing negative values then you would need a SELECT/CASE
                        for Storing and Scanning the Array. I don't think it would add much overhead.

                        Comment


                        • #13
                          Bary, Your proposal seems to be fine for now!

                          Bary, Your proposal seems to be a very good solution!
                          In fact, the array could also contain negative numbers for possible invalid items. But there are only used numbers from -1 ... -12. So I could predefine any other negative value. The problem however ist that the database is dynamically filled. So it could happen that it starts with index 1000000. I don't know the first index addressed by the process by start of the process. So I could for example fill all items with index 0...999999 with -99 for instance. As soon as a new value is added at 2000000 I have to fill all items between 1000001 and 1999999 afterwards. And so on. This handling is very much time consuming. But may be it could be usefull after some experiences with mass of data. I tried already predefining an array of 2000000 items with -99 which ran for a while until 2000000 were overridden.
                          The routine I'm writing is to cut out precisely an area defined by a polygon or bezier out of a vector drawing. I have to calculate all intersecting points of all kind of entity data. As often, the difficulties are not in the math materia but in finding the best way to handle it.
                          Norbert Doerre

                          Comment


                          • #14
                            Code:
                            because "Array Scan" is based on 1. That's correct.
                            Norbert,

                            The Array Scan return value is "the relative index of the first match". If there is no match found the result is 0. The relative index is the number of items Array Scan needed to find the match. Therefore, a return value of 1 means the first element scanned matched.

                            In order to relate the a matched values relative index to your array you must consider (1) the index of the starting element and (2) the "relative index" if a match is found. In the help file examples are shown, but a real world code example to relate the relative index to the actual array index of a match is not shown. So here's a couple of expanded examples:

                            Code:
                            Local MyIndx,iRet   As Long
                               ReDim c(10) As Long
                               c(1) = 11
                               c(2) = 12
                            MyIndx  = 0
                               Array Scan c(), =0, To iRet  
                            IF iRet > 0 Then
                                  'because to add the iRet  like an offset, the start element itself 
                                'should  not be included
                                Decr iRet 
                                'so if the start element is the matched element then the offset
                                'will not increase the actual index value of MyIndx
                                MyIndx = MyIndx + iRet  
                            End If
                            This also holds true if you search starting at an element other than the LBOUND.

                            Code:
                            Local MyIndx,iRet   As Long
                                ReDim c(10) As Long
                                c(1) = 11
                                c(2) = 12
                            MyIndx  = 5  'starting element in actua scan search
                                Array Scan c(5), =0, To iRet  
                            IF iRet > 0 Then
                                  'because to add the iRet  like an offset, the start element itself 
                                'should  not be included
                                Decr iRet 
                                'so if the start element is the matched element then the offset
                                'will not increase the actual index value of MyIndx
                                MyIndx = MyIndx + iRet  
                            End If
                            In the preceding example, Array Scan will return 1. But we adjust this in the If iRet = 0 block and the answer is 5, which is correct, since c(5) was initialized at zero.

                            Understanding this important principle will also lay the foundation for scanning an entire array for matching values:

                            Code:
                            LOCAL MyIndx,iRet,Matches AS LONG
                                LOCAL Finds AS STRING
                                REDIM c(10) AS LONG
                                ARRAY ASSIGN c() = 1,11,12,0,3,4,5,6,7,0,10
                                
                                MyIndx  = 0  'starting element in actua scan search
                                DO
                                    ARRAY SCAN c(MyIndx), =0, TO iRet
                                    IF iRet > 0 THEN
                                        'because to add the iRet like an offset, the start element itself
                                        'should  not be included
                                        DECR iRet
                                        'so if the start element is the matched element then the offset
                                        'will not increase the actual index value of MyIndx
                                        MyIndx = MyIndx + iRet
                                        Finds = Finds + STR$(MyIndx)
                                        INCR MyIndx 'start next scan at element after last match
                                        IF MyIndx > UBOUND(c()) THEN EXIT LOOP  'no endless loops
                                        INCR Matches
                                    ELSE
                                        EXIT LOOP
                                    END IF
                                LOOP
                                
                                ? "Matchs: " + STR$(Matches)+$CRLF+ "Indexes: " + Finds
                            Last edited by Richard Angell; 28 Aug 2008, 10:29 AM. Reason: Modified last example for explicit find illustration
                            Rick Angell

                            Comment


                            • #15
                              MAT to the rescue?

                              Hi Norbert,

                              It seems to me that nobody has read the entire post. The last example:
                              Code:
                              ReDim c(10)
                              c(0) = 10 
                              c(5) = 0
                              c(6) = 12
                              Array Scan c(), =0, To iRet 
                              'iRet = 1. This is not ok, because iRet = 1
                              'So, I cannot scan for a value = 0 which is essential to me.
                              ... would be totally against the documented behaviour, as c(0) <> 0. However, when I run this code, I get iRet = 2, not 1, so this appears to be a mistake on your part.

                              I think, from reading the whole thread, that your problem is that the array is initialized to 0 and you need to know whether a 0 is an "empty" item, or one you have assigned yourself. If that is the case, then could I suggest:

                              Code:
                              ReDim c(10)
                              MAT c() = CON(-1)
                              c(5) = 0
                              c(6) = 12
                              Array Scan c(), =0, To iRet
                              The MAT statement initializes the entire array to the expression in the brackets after CON - i.e. to -1. Obviously you could use whatever value is appropriate to allow you to distinguish it from your assigned values. In the above example, iRet = 6 (i.e. c(5) ) which is correct.

                              I hope that helps.

                              Regards,

                              Pete.

                              Comment


                              • #16
                                Norbert,
                                Do you have one of the new compilers?
                                I have Code using IDictionary of the Microsoft Scripting Runtime (scrrun.dll ) which might help.

                                Give a yell.

                                James

                                Comment


                                • #17
                                  @ Lee

                                  Lee, what You write was my first idea, too. But the routines handling all that are inside lots of include files which are used multiple times in my program. Until now, I did not need to search for zero. So more than 100 DLLs contain calls to these procedures. I fear to get many problems adding 1 to or substracting 1 from the item values. I'm however convinced that this is the correct way to do it.
                                  Norbert Doerre

                                  Comment


                                  • #18
                                    @James

                                    James, yes, my compiler is in fact PB9!
                                    Norbert Doerre

                                    Comment


                                    • #19
                                      Originally posted by norbert doerre View Post
                                      James, yes, my compiler is in fact PB9!
                                      Ok I'll put together a sample after lunch.I found in my testing that the IDictionary was faster than Paul Squires hash table up to about 25000(?) entries.

                                      James
                                      Last edited by jcfuller; 28 Aug 2008, 11:21 AM. Reason: Missed a zero

                                      Comment


                                      • #20
                                        @Rodnay

                                        Rodney, here a simple example, but it contents at least the array handling tied out. It is running well as long as no entity handle with zero is added to the array:
                                        Code:
                                        '-------------------------------------------------------------------------------------------------------
                                        ' FUNCTION EntitiesCrossingFence
                                        '-------------------------------------------------------------------------------------------------------
                                        Function EntitiesCrossingFence(dpFence() As POINT2D, CrossingH() As Long) As Long
                                        	'Handles von Elementen auflisten, die den Zaun kreuzen
                                        	'INPUT: dpFence() = Array mit den Zaunpunkten, tfSelClosed = unter der geschlossenen Kontur wird ebenfalls selektiert 
                                        	'OUTPUT: CrossingH) = Handle-Liste der kreuzenden Elemente
                                        	'Function = Anzahl der kreuzenden Elemente
                                        	Local i As Long
                                        	Local n As Long
                                        	Local iError As Integer
                                           Local iSeg As Long
                                           Local iRet As Long
                                           Local iEntKind As Integer
                                           Local iCount As Long
                                           Local EntH As Long
                                           Local iFencePts As Long
                                           Dim dpSeg() As POINT2D
                                        	Function = 0   
                                        	ReDim CrossingH(0)
                                        	VCDeselectAll()
                                        	iFencePts = UBound(dpFence) 'Anzahl der Zaunpunkte
                                           'Prüfen, ob die selektierten Elemente eines der Zaunsegmente schneiden.
                                        	iSeg = 200 'Anzahl der zu erzeugenden Segmente entlang jeder Selektionskontur von dpFence
                                        	iCount = 0
                                        	For i = 0 To iFencePts - 2
                                        		ReDim dpSeg(iSeg) 'Array der zu erzeugenden Punkte
                                        		iRet = maDivideLinePnt(dpFence(i), dpFence(i + 1), iSeg, dpSeg()) 'Auf dem Selektionssegment dpFence(i) iSeg Minisegmente erzeugen
                                        		For n = 0 To iSeg - 1 'mit den erzeugten Segmenten als Kette von Selektionsfenstern kreuzend selektieren
                                        			MCCrossingSelect(dpSeg(n), dpSeg(n+1))
                                        			If MCSelectedFirst(iError, iEntKind) Then
                                        				Do While iError = 0
                                        				   MCSetCurrentDeselected(iError)
                                        					If iEntKind <> %UNKNOWN Then
                                        						EntH = MCGetCurrEntHandle(iError)
                                        '						If UBound(CrossingH()) > 0 Then
                                        						   Array Scan CrossingH(), =EntH, To iRet 'iRet zählt mit der Basis 1, CrossingH mit der Basis 0
                                                             MsgBox "iRet: " & Str$(iRet)					
                                                             If iRet = 0 Then 'Wenn iRet = 0, dann ist Element EntH noch nicht in CrossingH() enthalten, dann sichern
                                        						      ReDim Preserve CrossingH(iCount + 1)
                                        						      CrossingH(iCount) = EntH
                                        						      iCount = iCount + 1
                                        						   End If
                                        '						End If
                                        						If MCSelectedNext(iError, iEntKind) Then
                                        						End If 
                                        					End If
                                        				Loop
                                        			End If
                                        		Next n
                                        		ReDim dpSeg(0) 'zurücksetzen
                                        	Next i
                                        	Function = iCount
                                        End Function
                                        Norbert Doerre

                                        Comment

                                        Working...
                                        X