Page 1 of 2

AScan() a Multi-Dimensional Array

Posted: Thu Nov 24, 2022 2:37 am
by Red2
I need to AScan() a multi-dimensional array. It should be easy but I need your kind guidance.

// With a numeric 3-D array as follows:
LOCAL laPrimeCounts := { {10,1,0.1}, {100,25,0.2}, {1000,168,0.3}, {10000,1229,0.4}, {100000,9592,0.5}, ;
{1000000,78498,0.6}, {10000000,664579,0.7}, {100000000,5761455,0.8} }

// Example: My lines below return 0 (rather than the row #2):
lnColumn1_Hit := AScan( laPrimeCounts, 100 ) // Returns 0
lnColumn2_Hit := AScan( laPrimeCounts, 25 ) // Returns 0
lnColumn3_Hit := AScan( laPrimeCounts, 0.2 ) // Returns 0

QUESTION:
How can I AScan() an N-Dimension array (2-D, 3-D, or 4-D ) to identify the array row containing a value in a particular column?
I assume such a solution adapts for a character array, correct?

Thank you for your genereous help!

Red2

Re: AScan() a Multi-Dimensional Array

Posted: Thu Nov 24, 2022 8:07 am
by serge_girard
Red2,

Personnaly I would NOT use ASCAN...
I prefer my own little routine:

Code: Select all

FUNCTION MAIN()
/******************/
LOCAL laPrimeCounts := { ;
{10,1,0.1}, ;
{100,25,0.2}, ;
{1000,168,0.3}, ;
{10000,1229,0.4}, ;
{100000,9592,0.5}, ;
{1000000,78498,0.6}, ;
{10000000,664579,0.7}, ;
{100000000,5761455,0.8} }

SET PRINTER TO C:\test\SCAN.TXT
SET PRINTER ON 
SET CONSOLE OFF  



aSEARCH := {}
AADD(aSEARCH, 10000)    // FOUND
AADD(aSEARCH, 664579)   // FOUND
AADD(aSEARCH, 62364579) // NOT FOUND
AADD(aSEARCH, .03)      // NOT FOUND
AADD(aSEARCH, .300)     // FOUND

FOR xx :=  1 to len(aSEARCH)
   nSEARCH := aSEARCH [XX]
   FOR a := 1 to len(laPrimeCounts)
    
      FOR b := 1 to len(laPrimeCounts [a] )
         IF laPrimeCounts [a,b ] == nSEARCH
            ? 'found', laPrimeCounts [a,b ]
         ENDIF
         
      NEXT 
   NEXT
NEXT
QUIT
This works very fine and easy to expand!

Serge

Re: AScan() a Multi-Dimensional Array

Posted: Thu Nov 24, 2022 2:08 pm
by Red2
Thank you very much Serge.

I can manually write code to iterate through an array's specific column.
I guess that what I really want to know is does the HMG syntax,
ASCAN( <aTarget>, <xSearch>, [<nStart>], [<nCount>] ) --> nStoppedAt
only support a 1-Dimensional array?

As of Visual FoxPro's version 7 one could specify the column to be scanned:
nResult = ASCAN( ArrayName, uExpression [, nStart [, nNumElems [, nColumn [, nFlags ] ] ] ] )

QUESTION:
Was column searching of a Multi-Dimensional array ever implemented in HMG or Harbour in a function?
If so I would appreciate it if the function and it's syntax would be shared.

Thanks again for all of your expert HMG guidance.
Red2

Re: AScan() a Multi-Dimensional Array

Posted: Thu Nov 24, 2022 2:18 pm
by serge_girard

Re: AScan() a Multi-Dimensional Array

Posted: Thu Nov 24, 2022 5:41 pm
by Red2
Thank you very much Serge for your help! I have looked at both of the URLs.
Only https://harbour.github.io/doc/harbour.html#ascan
has a Multi-Dimensional example.

I am confused. When running either the 1) the web page's interactive example or
when running the example code 2) locally on my machine the result returned (by both) is 0.

Code: Select all

#include "directry.ch"
LOCAL nStoppedAt
LOCAL aDir := hb_vfDirectory( "*.prg" )
//
nStoppedAt := AScan( aDir,,, {| aFile, nPos | HB_SYMBOL_UNUSED( nPos ), aFile[ F_NAME ] == "Main.prg" } )
msginfo( "Result:  " + NtoC( nStoppedAt )	// Returns 0
What mistakes am I making? Is something else going on?

I still have not been able to successfully run AScan() on my array locally:

Code: Select all

LOCAL laPrimeCounts := { {10,1}, {100,25}, {1000,168}, {10000,1229}, {100000,9592} ;
					,	 {1000000,78498}, {10000000,664579}, {100000000,5761455} }
lnHit := AScan( laPrimeCounts, 100, 1 )  // Returns 0
Perhaps I do not understand AScan's syntax:
nStoppedAt := AScan( <aArray>, <xSearch>, [<nStart>], [<nCount>] )
aArray: Array to be scanned.
xSearch: Expression to search for in aTarget
nStart: Beginning subscript position at which to start the search.
nCount: Number of elements to scan with aTarget.
Does nStart refer to, the column number or row number?

Thanks again. Any suggestion that help me understand would be greatly appreciated.
Red2

Re: AScan() a Multi-Dimensional Array

Posted: Thu Nov 24, 2022 11:11 pm
by serge_girard
To be honest: I don't use ASCAN... I use my own FOR-NEXT loops! I always had a problem with ASCAN. Maybe somebody else knows right syntax/use.

Serge

Re: AScan() a Multi-Dimensional Array

Posted: Fri Nov 25, 2022 4:33 am
by AUGE_OHR
hi Red

search Filename in DIRECTORY Array

Code: Select all

  aDir := DIRECTORY( cPath + "*.*", "DHS" )
  nPosi := ASCAN( aDir, { | x | lower(x[ F_NAME ]) = lower(cFile) } )
sort DIRECTORY Array to have "D" on Top

Code: Select all

  // "D"irectry on Top
  ASORT( aDir,,, { | x, y | "D" $ x[ F_ATTR ] } )
  AEVAL( aDir, { | x, i | nStartAt := IF( "D" $ x[ F_ATTR ], i, nStartAt ) } )
  ASORT( aDir, 1, nStartAt, { | x, y | LOWER( x[ F_NAME ] ) < LOWER( y[ F_NAME ] ) } )
  //now sort Size
  IF ::SortOrder = LVS_SORTASCENDING
      ASORT( aDirOut, nStartAt + 1,, { | x, y | ( x[ F_SIZE ] ) < ( y[ F_SIZE ] ) } )
  ELSE
      ASORT( aDirOut, nStartAt + 1,, { | x, y | ( x[ F_SIZE ] ) > ( y[ F_SIZE ] ) } )
  ENDIF
Red2 wrote: Thu Nov 24, 2022 5:41 pm Does nStart refer to, the column number or row number?
on ROW

Re: AScan() a Multi-Dimensional Array

Posted: Fri Nov 25, 2022 7:16 am
by anupamgaurav22
Hi Red

you can try below code -

Code: Select all

LOCAL laPrimeCounts := { {10,1,0.1} ,; 
                         {100,25,0.2},;
                         {1000,168,0.3},;
                         {10000,1229,0.4},;
                         {100000,9592,0.5},;
                         {1000000,78498,0.6},;
                         {10000000,664579,0.7},;
                         {100000000,5761455,0.8} }


? AScan( laPrimeCounts, { |arr| arr[1]==100 } )
? AScan( laPrimeCounts, { |arr| arr[2]==25 } )
? AScan( laPrimeCounts, { |arr| arr[3]==0.5 } )

Anupam

Re: AScan() a Multi-Dimensional Array

Posted: Fri Nov 25, 2022 7:54 am
by serge_girard
anupamgaurav22 solution is OK but.....

Code: Select all

LOCAL laPrimeCounts := { {10,1,0.1} ,; 
                         {100,25,0.2},;
                         {1000,168,0.3},;
                         {10000,1229,0.4},;
                         {100000,9592,0.5},;
                         {100000,1119592,0.5},;
                         {100000,9522222292,0.5},;
                         {1000000,78498,0.6},;
                         {10000000,664579,0.7},;
                         {100000000,5761455,0.8} }

? AScan( laPrimeCounts, { |arr| arr[1]==100 } )
? AScan( laPrimeCounts, { |arr| arr[2]==25 } )
? AScan( laPrimeCounts, { |arr| arr[3]==0.5 } )



It will only find FIRST appearance of 0.5 in this array. My LOOP construction will find every appearance.
Or is there some flag missing saying all appearances?

S

Re: AScan() a Multi-Dimensional Array

Posted: Fri Nov 25, 2022 5:24 pm
by Red2
Hello all,

Serge's solution can identify a value in more than 1 array row. Thanks!
Jimmy's showed me interesting ways to manipulate arrays. Thanks!

Thank you anupamgaurav22! You taught me the AScan() syntax I needed for Multi-Dimensional array lookups.
This is exactly what I wanted. (Coming from a VFP background, code blocks are something I am slowly learning).

For what it is worth, this all came about from viewing the following video.
It challenged me to create, using the HMG language, the fastest Prime Number generator program I could.

"E00: Software Drag Racing: C++ vs C# vs Python - Which Will Win?"
https://www.youtube.com/watch?v=D3h62rgewZM&t=717s


There are two considerations, the most efficient algorithm and the best use of a programming language.
I may not have accomplished either but it has been a great learning experience.
Interestingly using the same .PRG my results showed Official HMG was 1.29% faster than HMG Extended.

In case anyone is interested I plan on posting my "HMG" code in a day or two (after a little cleanup).

Thanks again for everyone's help!
Red2