Jump to content
Triblade

Array read speed vs variable made from array

Recommended Posts

Triblade

Hi all,

 

I was pondering over a question with regards to the speeds of reading something and did not see this kind of question in a forum search.

The question: What is (technically) faster? Multiple reads from the same 3d array cell, or only once make a 'temp' variable from that cell and read the value from this? I don't know if either has any real impact at all anyway, but just wanted to ask anyway. :-)

 

There may be a difference if the value holds an integer or a string (or something else) but in my case, is a simple integer.

To hopefully clarify with a small bit of code:

$process = $start - 15
If $xy[$process][3] <> "x" Then
    If _ArraySearch($open, $process, 1, $open[0][0], 0, 0, 1, 1) <> -1 Then
        UpdateOpen($xy[$process][5], $closed[0][0])
    ElseIf $start > 0 And _ArraySearch($closed, $process, 1, $closed[0][0], 0, 0, 1, 0) = -1 Then
        Add_open($start, $closed[0][0], $counter, $process)
    EndIf
EndIf

You can read from this, that the array $closed[0][0] is being read 3 times. And this goes on further in the code I did not show.

My question boils down to this, should I make a 'temp' variable to hold that $closed[0][0] value until the function is done?

 

It may not have a real impact on my small script, but I really am interested in the answer at least.

 

Regards,

Tri.

  • Like 1

My active project(s): A-maze-ing generator (generates a maze)

My archived project(s): Pong3 (Multi-pinger)

Share this post


Link to post
Share on other sites
spudw2k

I did a quick perf test, and there does not appear to be a major disadvantage either way from what I can tell.  Assigning a local variable instead of accessing the array is barely faster...and not always based on my test script.

#INCLUDE <ARRAY.AU3>
_ArrayReadTest1()
_ArrayReadTest2()


Local $iTime1 = 0
Local $iTime2 = 0
For $iZ = 1 to 10
    $iValue1 = Random(100,1000,1)
    $iValue2 = Random(1,10,1)

    $iTime1 += _ArrayReadTest1($iValue1,$iValue2)
    $iTime2 += _ArrayReadTest2($iValue1,$iValue2)
Next

$iTime1 = $iTime1 / 10
$iTime2 = $iTime2 / 10

ConsoleWrite("ArrayReadTest1 Average Time: " & $iTime1 & @CRLF)
ConsoleWrite("ArrayReadTest2 Average Time: " & $iTime2 & @CRLF)

Func _ArrayReadTest1($iArrayDimension1=10,$iArrayDimension2=3)
    ConsoleWrite("ArrayReadTest1" & @CRLF)
    ;Create Array for Testing
    Local $aData[$iArrayDimension1][$iArrayDimension2]
    For $iX = 0 to $iArrayDimension1-1
        For $iY = 0 to $iArrayDimension2-1
            $aData[$iX][$iY] = "Blah"
        Next
    Next
    Local $iDim1 = Random(0,$iArrayDimension1-1,1)
    Local $iDim2 = Random(0,$iArrayDimension2-1,1)
    ;Time Measurement
    Local $hTimer = TimerInit()
    ConsoleWrite($aData[$iDim1][$iDim2] & @TAB)
    ConsoleWrite($aData[$iDim1][$iDim2] & @TAB)
    ConsoleWrite($aData[$iDim1][$iDim2] & @CRLF)
    Local $iTime = TimerDiff($hTimer)
    ConsoleWrite("Duration: " & $iTime & @CRLF & @CRLF)
    $hTimer = 0
    Return $iTime
EndFunc

Func _ArrayReadTest2($iArrayDimension1=10,$iArrayDimension2=3)
    ConsoleWrite("ArrayReadTest2" & @CRLF)
    ;Create Array for Testing
    Local $aData[$iArrayDimension1][$iArrayDimension2]
    For $iX = 0 to $iArrayDimension1-1
        For $iY = 0 to $iArrayDimension2-1
            $aData[$iX][$iY] = "Blah"
        Next
    Next
    Local $iDim1 = Random(0,$iArrayDimension1-1,1)
    Local $iDim2 = Random(0,$iArrayDimension2-1,1)
    ;Time Measurement
    Local $hTimer = TimerInit()
    Local $iValue = $aData[$iDim1][$iDim2]
    ConsoleWrite($iValue & @TAB)
    ConsoleWrite($iValue & @TAB)
    ConsoleWrite($iValue & @CRLF)
    Local $iTime = TimerDiff($hTimer)
    ConsoleWrite("Duration: " & $iTime & @CRLF & @CRLF)
    $hTimer = 0
    Return $iTime
EndFunc


So performance wise, I don;t think it matters too much (unless my test logic is flawed).  Depending on the script and code, you may want to assign a local variable to capture a state of the array index if background tasks may/will update the array.  

Edited by spudw2k

Share this post


Link to post
Share on other sites
jvanegmond

Triblade, what an interesting question.

Under the waters, any array is just an address of where to start finding the values in memory. Say you're storing 32-bit integers in an array, this will be stored in a contiguous block of memory. If we were to look at the memory, it would look like:

base address (start) and then 4 bytes integer, 4 bytes integer, 4 bytes integer, and so on.

If the base address of this array is 50, array index 2 is going to be at 50 + (2 x 4) where 4 is the size in bytes of the integer. In statically typed languages, the number of bytes for your value is determined at compile time so this can be 'baked' into the program to avoid any calculations. In AutoIt, a dynamically typed language, there exists something called a variant (based on 2005 source but probably not changed) which can store any type of data: Int, long, double, window handle, and such small data types easily fit in the variant structure. These are stored sequentially for optimization reasons with a minor overhead. Large values such as strings are stored in another location and the variant simply holds the address to this string memory, so this types of data are exceptional and should be considered carefully when thinking about performance.

Multidimensional arrays get turned into flat arrays, where the indexes are multiplied by one another. So $closed[3][4] is just $closed base address + ((3 * 4) * 4). Again taking 4 bytes for each integer. So you can consider $closed[3][4] to be another syntax for $closed[3*4]. This is really not a special case for the underlying language.

The CPU is incredibly fast. He always copies data from RAM to cache in sizes which are called a block. This is mostly 4K of memory at once copied from RAM, which take about 120+ CPU cycles to get into cache. Modern CPU have 3 levels of cache, called L3, L2 and L1. Depending on manufacturer, these caches have different sizes and this is a large contributor into what makes some modern CPU's feel fast and some slow apart from just raw clock speed.

Accessing arrays requires the CPU to multiply the indexes and then get the whole block of memory into cache. Multiplying the dimensions for your array in your script, 0 by 0, is trivial. This takes only 1 or 2 CPU cycles. Actually retrieving the memory from RAM takes 120+ cycles. Once this memory is in cache, it will take less than 20 CPU cycles to retrieve it again. How do we know if memory is still in cache? This depends on a lot of factors, but the main factor here is your operating system.

Your operating system slices the total CPU time up into what are called slices. Each thread on the operating system gets a time slice according to some prioritization mechanism. Familiarity with this might include opening up task manager, seeing the total amount of threads on the system, and changing the priority of a process to High or Realtime. Now do not be alarmed at the 2000+ something threads running on your system. A vast majority of these threads are in sleep mode, and the scheduler simply skips over them.

Our program will be executing within one of these time slices. This means at the start of the time slice, our CPU will get RAM into cache and will as quickly as possible execute our program. The realistic expected time frame of accesses to the same point in memory should be around 120 cycles for the first access and 20 cycles afterwards. As long as we write our code in tight loops, where we are not voluntarily relinquishing CPU time back to the operating system when we are waiting for something, our data should still be in cache.

Realistically, data still being in cache is determined by a cache eviction policy/algorithm and there is really nothing you can do about this other than not submit to thread switches and perhaps write a nice letter to Intel/AMD where you offer a couple of beers and to sacrifice a goat. Each vendor individually has their own cache eviction policy and I believe in x86 or x86-64 these are not standardized and therefore make for a source of competition for these companies.(Citation needed)

Strings and large memory structures are special. In this case, the variant does not hold the data directly but holds a reference to where the data is really stored. This means the CPU must get the array from memory, which points to other blocks of memory which must also be gotten from RAM. This means not only one of those terrible 120+ cycle accesses, but several, just to access one item. There is really no good solution for this with arrays. Other data types which allow elements to be of non-uniform length might be better suited for the application. This is more or less the same for statically typed languages.

THIS COVERS ARRAY ACCESS.

Now keep in mind that code is just another form of data. The code must also be read into CPU cache before it can be executed. If the AutoIt language makes some bad choices regarding caches; this will severely impact performance and may invalidate some or all of the above. For example, code pointing to other code, to other code, which must all be gotten from cache in sequence is going to make a practical program - which follows all the correct performance guidelines - very, very slow. This is why the community prefers to do benchmarks - but there's nothing wrong with a little theory from time to time.

I believe AutoIt to do this mostly pretty OK in practice. The AutoIt source from 2005 seems to confirm this and that's really the best I can do on this part.

Disclaimer: I've had to dumb this down, and only somewhat reflects the intricacies of modern computing.

  • Like 1

Share this post


Link to post
Share on other sites
Triblade
On 3/2/2017 at 4:36 AM, spudw2k said:

I did a quick perf test, and there does not appear to be a major disadvantage either way from what I can tell.  [...]

So performance wise, I don;t think it matters too much (unless my test logic is flawed).

Thanks for the test setup! :)

It seems to gives a small advantage to the read of the variable. See the answer of jvanegmond for a probable cause.

(I did move the setting of the variable before the timestart btw.)

 

10 hours ago, jvanegmond said:

Triblade, what an interesting question.

Under the waters, any array is just an address of where to start finding the values in memory. Say you're storing 32-bit integers in an array, this will be stored in a contiguous block of memory. If we were to look at the memory, it would look like:

base address (start) and then 4 bytes integer, 4 bytes integer, 4 bytes integer, and so on.

Multidimensional arrays get turned into flat arrays, where the indexes are multiplied by one another. So $closed[3][4] is just $closed base address + ((3 * 4) * 4). Again taking 4 bytes for each integer. So you can consider $closed[3][4] to be another syntax for $closed[3*4].

The CPU is incredibly fast. He always copies data from RAM to cache in sizes which are called a block. This is mostly 4K of memory at once copied from RAM, which take about 120+ CPU cycles to get into cache.

Accessing arrays requires the CPU to multiply the indexes and then get the whole block of memory into cache.

Our program will be executing within one of these time slices. This means at the start of the time slice, our CPU will get RAM into cache and will as quickly as possible execute our program. The realistic expected time frame of accesses to the same point in memory should be around 120 cycles for the first access and 20 cycles afterwards. As long as we write our code in tight loops, where we are not voluntarily relinquishing CPU time back to the operating system when we are waiting for something, our data should still be in cache.

Strings and large memory structures are special.

Disclaimer: I've had to dumb this down, and only somewhat reflects the intricacies of modern computing.

* I've cut out a lot of text in the quote because of saving space, and my answers/questions are directly related to the left over sentences. I absolutely did not skip anything.


It may be an interesting question, but an even much more interesting explanation! Thank you for the trouble!

If I understand the gist of it, a variable or an array with integers are both handled the same in that they reside in RAM and get moved for processing to the CPU caches if they are not too large. This means that the slice of CPU that processes the lot have the same amount of cycles needed to get either variable or array cell since they occupy the same cache environment.

The only thing that could explain the 'slower' array speed in the example spudw2k made is the multiplying the CPU has to do to put the array in the cache in the format it needs. I'm 70% sure I've figured this out by dissecting your explanation.

I understand the need for dumbing this down, I had to read this a few times over to process. ^_^

 

Is the gist I wrote about correct?


My active project(s): A-maze-ing generator (generates a maze)

My archived project(s): Pong3 (Multi-pinger)

Share this post


Link to post
Share on other sites
jvanegmond

Your gist understanding is correct. Except when the array is too large to fit, for example it spans 1 contiguous block of 100MB, this array will just be read into the CPU cache at page-size blocks at a time based on the subscripts you are accessing. This is why sequentially accessing an array is faster than randomly accessing it. The data for the next element will already be in cache.

The test which spudw2k did unfortunately has some problems which make interpreting any meaningful result from it difficult. The array is reinitialized and then accessed immediately after, which can leave the array in the cache. But this depends on CPU make & model. Random numbers are generated in a non-deterministic way, which can affect the outcome of each new test. 10 samples taken is not nearly enough to eliminate random noise, from other programs and the operating system. Probably TimerInit/TimerDiff should be replaced for all such performance measurement scenarios with a straight up call to a QueryPerformanceCounter function, but then DllCall is kinda slow too so it's a lesser of evils decision. There are more problems, none are easy to really properly compensate for.

AutoIt is in this sense not designed with such small performance thoughts in mind. It's better to focus on things we know which will have an affect on performance. Having the data already in cache is referred to as locality of reference and can help in a big way in your initial example. It shouldn't really matter if you copied it into a temporary variable or are accessing it directly, it matters that its in cache or no.

  • Like 1

Share this post


Link to post
Share on other sites
Triblade

I understand the principle now at last, that principle is the important takeaway.

My script/arrays is probably never going to be big enough to have to stay in RAM I think, but now I know that because of this thread :P

 

I do think the test could be useful in my specific case, because I intend my script to reset the array and then run again when needed.

 

So, thanks again for the confirmation and interesting material! :D


My active project(s): A-maze-ing generator (generates a maze)

My archived project(s): Pong3 (Multi-pinger)

Share this post


Link to post
Share on other sites
LarsJ

How much does a few hundred CPU cycles more or less mean if the AutoIt code interpreter needs millions of CPU cycles to interpret a single line of AutoIt code?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • rm4453
      By rm4453
      I have a table I am parsing, to find specific vehicle information. I am unable to get _ArrayFindAll to return the only valid result with my test data.
      Below is a sample of the table's HTML:
      <td class="textCenter">2010</td> <td>TOYOTA</td> <td>TACOMA 4X4 DB</td> <td></td> <td>BLACK</td> <td class="textCenter">C</td> <td class="textCenter">6</td> <td>GAS</td> <td class="textCenter">A</td> <td class="textCenter">4X4</td> <td class="textCenter">Y</td> <td>CD</td> <td class="textCenter">HT</td> <td class="textCenter">C</td> <td class="textRight" nowrap="nowrap">80,975</td> <td class="textRight" nowrap="nowrap">$16,800</td> </tr> <tr><!-- 308 --> <td class="textCenter">2010</td> <td>TOYOTA</td> <td>TACOMA 4X4 RG</td> <td></td> <td>BLACK</td> <td class="textCenter">R</td> <td class="textCenter">4</td> <td>GAS</td> <td class="textCenter">5</td> <td class="textCenter">4X4</td> <td class="textCenter">A</td> <td>CD</td> <td class="textCenter">HT</td> <td class="textCenter">C</td> <td class="textRight" nowrap="nowrap">95,224</td> <td class="textRight" nowrap="nowrap">$9,500</td> </tr> <tr><!-- 309 --> <td class="textCenter">2011</td> <td>BUICK</td> <td>REGAL</td> <td>CXL RL4</td> <td>BLACK</td> <td class="textCenter">4</td> <td class="textCenter">4</td> <td>GAS</td> <td class="textCenter">A</td> <td class="textCenter"></td> <td class="textCenter">A</td> <td>CD</td> <td class="textCenter">SR</td> <td class="textCenter">L</td> <td class="textRight" nowrap="nowrap">102,694</td> <td class="textRight" nowrap="nowrap">$5,000</td> </tr> <tr><!-- 310 --> <td class="textCenter">2011</td> <td>CHEVROLET</td> <td>AVALANCH 4X4 CR</td> <td>LS</td> <td>GRAY</td> <td class="textCenter">C</td> <td class="textCenter">8</td> <td>E</td> <td class="textCenter">A</td> <td class="textCenter">4X4</td> <td class="textCenter">A</td> <td>CD</td> <td class="textCenter">HT</td> <td class="textCenter">C</td> <td class="textRight" nowrap="nowrap">64,759</td> <td class="textRight" nowrap="nowrap">$16,300</td> </tr> <tr><!-- 311 --> <td class="textCenter">2011</td> <td>CHEVROLET</td> <td>EQUINOX AWD 4C</td> <td>LT W/2LT</td> <td>BLACK</td> <td class="textCenter">S</td> <td class="textCenter">4</td> <td>GAS</td> <td class="textCenter">A</td> <td class="textCenter">AWD</td> <td class="textCenter">Y</td> <td>CD</td> <td class="textCenter">SR</td> <td class="textCenter">C</td> <td class="textRight" nowrap="nowrap">91,896</td> <td class="textRight" nowrap="nowrap">$4,400</td> </tr> <tr><!-- 312 --> <td class="textCenter">2011</td> <td>CHEVROLET</td> <td>TAHOE 4X4 V8</td> <td>LTZ</td> <td>WHITE</td> <td class="textCenter">S</td> <td class="textCenter">8</td> <td>C</td> <td class="textCenter">A</td> <td class="textCenter">4X4</td> <td class="textCenter">A</td> <td>N</td> <td class="textCenter">MR</td> <td class="textCenter">L</td> <td class="textRight" nowrap="nowrap">126,982</td> <td class="textRight" nowrap="nowrap">$17,800</td> </tr> <tr><!-- 313 --> <td class="textCenter">2011</td> <td>CHEVROLET</td> <td>1500 SLV 4X4 EX</td> <td>LT</td> <td>GRAY</td> <td class="textCenter">X</td> <td class="textCenter">8</td> <td>GAS</td> <td class="textCenter">O</td> <td class="textCenter">4X4</td> <td class="textCenter">A</td> <td>CD</td> <td class="textCenter">HT</td> <td class="textCenter">C</td> <td class="textRight" nowrap="nowrap">60,303</td> <td class="textRight" nowrap="nowrap">$18,100</td> </tr> <tr><!-- 314 --> <td class="textCenter">2011</td> <td>CHEVROLET</td> <td>1500 SLV 4X4 EX</td> <td>LT</td> <td>SILVER</td> <td class="textCenter">X</td> <td class="textCenter">8</td> <td>E</td> <td class="textCenter">O</td> <td class="textCenter">4X4</td> <td class="textCenter">A</td> <td>CD</td> <td class="textCenter">HT</td> <td class="textCenter">C</td> <td class="textRight" nowrap="nowrap">89,403</td> <td class="textRight" nowrap="nowrap">$15,900</td> </tr> <tr><!-- 315 --> <td class="textCenter">2011</td> <td>CHEVROLET</td> <td>1500 SLV 4X4 EX</td> <td>LTZ</td> <td>BLUE</td> <td class="textCenter">X</td> <td class="textCenter">8</td> <td>E</td> <td class="textCenter">A</td> <td class="textCenter">4X4</td> <td class="textCenter">A</td> <td>CD</td> <td class="textCenter">HT</td> <td class="textCenter">L</td> <td class="textRight" nowrap="nowrap">53,087</td> <td class="textRight" nowrap="nowrap">$17,700</td> </tr> <tr><!-- 316 --> <td class="textCenter">2011</td> <td>CHEVROLET</td> <td>3500 CUTAWAY</td> <td>WORK VAN</td> <td>WHITE</td> <td class="textCenter">S</td> <td class="textCenter"></td> <td></td> <td class="textCenter">A</td> <td class="textCenter">4X2</td> <td class="textCenter"></td> <td>N</td> <td class="textCenter">HT</td> <td class="textCenter">C</td> <td class="textRight" nowrap="nowrap">202,477</td> <td class="textRight" nowrap="nowrap">$2,700</td> </tr> <tr><!-- 317 --> <td class="textCenter">2011</td> <td>CHRYSLER</td> <td>TOWN &amp; COUNTRY</td> <td>TOURING</td> <td>BLACK</td> <td class="textCenter">4</td> <td class="textCenter">6</td> <td>E</td> <td class="textCenter">A</td> <td class="textCenter">4X2</td> <td class="textCenter">A</td> <td>CD</td> <td class="textCenter">HT</td> <td class="textCenter"></td> <td class="textRight" nowrap="nowrap">198,541</td> <td class="textRight" nowrap="nowrap">$1,900</td> </tr> <tr><!-- 318 --> <td class="textCenter">2011</td> <td>DODGE</td> <td>DURANGO AWD V6</td> <td>CREW</td> <td>BLUE</td> <td class="textCenter">S</td> <td class="textCenter">6</td> <td>GAS</td> <td class="textCenter">A</td> <td class="textCenter">AWD</td> <td class="textCenter">A</td> <td>CD</td> <td class="textCenter">SR</td> <td class="textCenter">C</td> <td class="textRight" nowrap="nowrap">176,036</td> <td class="textRight" nowrap="nowrap">$2,800</td> </tr> <tr><!-- 319 --> <td class="textCenter">2011</td> <td>FORD</td> <td>FOCUS</td> <td>SE</td> <td>SILVER</td> <td class="textCenter">4</td> <td class="textCenter">4</td> <td>GAS</td> <td class="textCenter">A</td> <td class="textCenter"></td> <td class="textCenter">Y</td> <td>CD</td> <td class="textCenter">HT</td> <td class="textCenter">C</td> <td class="textRight" nowrap="nowrap">101,929</td> <td class="textRight" nowrap="nowrap">$3,100</td> </tr> <tr><!-- 320 --> <td class="textCenter">2011</td> <td>FORD</td> <td>FUSION FWD 4C</td> <td>SEL</td> <td>WHITE</td> <td class="textCenter">4</td> <td class="textCenter">4</td> <td>GAS</td> <td class="textCenter">A</td> <td class="textCenter"></td> <td class="textCenter">Y</td> <td>CD</td> <td class="textCenter">SR</td> <td class="textCenter">L</td> <td class="textRight" nowrap="nowrap">78,290</td> <td class="textRight" nowrap="nowrap">$5,500</td> </tr> <tr><!-- 321 --> <td class="textCenter">2011</td> <td>FORD</td> <td>F150 4X4 CR</td> <td>XLT</td> <td>BLACK</td> <td class="textCenter">C</td> <td class="textCenter">8</td> <td>GAS</td> <td class="textCenter">A</td> <td class="textCenter">4X4</td> <td class="textCenter">Y</td> <td>CD</td> <td class="textCenter">HT</td> <td class="textCenter">C</td> <td class="textRight" nowrap="nowrap">70,909</td> <td class="textRight" nowrap="nowrap">$16,000</td> </tr> <tr><!-- 322 --> <td class="textCenter">2011</td> <td>FORD</td> <td>MUSTANG V6 CPE</td> <td>V6 PREMIUM</td> <td>BLACK</td> <td class="textCenter">2</td> <td class="textCenter">6</td> <td>GAS</td> <td class="textCenter">A</td> <td class="textCenter">4X2</td> <td class="textCenter">A</td> <td>CD</td> <td class="textCenter">HT</td> <td class="textCenter">L</td> <td class="textRight" nowrap="nowrap">92,531</td> <td class="textRight" nowrap="nowrap">$2,700</td> </tr> <tr><!-- 323 --> <td class="textCenter">2011</td> <td>GMC</td> <td>ACADIA FWD</td> <td>SLE</td> <td>RED</td> <td class="textCenter">4</td> <td class="textCenter">6</td> <td>GAS</td> <td class="textCenter">A</td> <td class="textCenter"></td> <td class="textCenter">A</td> <td>CD</td> <td class="textCenter">HT</td> <td class="textCenter">C</td> <td class="textRight" nowrap="nowrap">79,199</td> <td class="textRight" nowrap="nowrap">$10,700</td> A picture of the table test data is attached here:

      Here is the _query function, and all other relevant code that I can share.
       
      Func _query($aSel, $aUrls) $oIE = _login() If $oIE = "Return" Then Return EndIf $j = 0 While $j < UBound($aSel) - 1 $i = 1 $aucID ;Unable To Share What This Is Other Than Var Name. _IENavigate($oIE, "Something" & $aucID[0] & "Something") _IELoadWait($oIE, 100, 2000) $oObj = _IETableGetCollection($oIE, 3) $cars = _IETableWriteToArray_ProgressBar($oObj, True, "Processing Requested Information!") ;<---- Modified Version See Post For It: https://www.autoitscript.com/forum/topic/195335-solved-how-to-add-a-progress-bar-to-_ietablewritetoarray/?tab=comments#comment-1400699 $carsYear = _filter($cars, 0, 0, GUICtrlRead($year)) $carsMake = _filter($carsYear, 0, 1, GUICtrlRead($make)) Global $carsModel = _filter($carsMake, 0, 2, GUICtrlRead($model)) $i = 0 $engine = GUICtrlRead($engine) If $engine <> "" Then While $i < StringLen($engine) $carsEngine = _filter($carsModel, 0, 6 + $i, StringLeft($engine, 1)) ;_ArrayDisplay($carsModel, "Cars Model Before Array Delete") $x = 1 While $x <= UBound($carsModel) _ArrayDelete($carsModel, $x) $x += 1 WEnd ;_ArrayDisplay($carsModel, "Cars Model After Array Delete") ;_ArrayConcatenate($carsModel, $carsEngine) ;_ArrayDisplay($carsModel, "Cars Model After Concatenate") $engine = StringTrimLeft($engine, 1) $i += 1 WEnd Else Dim $carsEngine[1][16] EndIf _ArrayConcatenate($carsEngine, $carsModel) _ArrayDisplay($carsEngine, "Cars Engine") Dim $carsDriveTrain[1][16] Dim $carsDriveTrain2[1][16] $driveTrainVal = GUICtrlRead($driveTrain) If $driveTrainVal = "4x4" Or $driveTrainVal = "awd" Then $carsDriveTrain = _filter($carsEngine, 0, 9, "4") $carsDriveTrain2 = _filter($carsEngine, 0, 9, "a") ;~ _ArrayDisplay($carsDriveTrain, "Drive Train Before") ;~ If @error Then ;~ MsgBox("", "", "Cars Drive Train Error: " & @error) ;~ EndIf ;~ _ArrayDisplay($carsDriveTrain2, "Drive Train2 Before") ;~ If @error Then ;~ MsgBox("", "", "Cars Drive Train 2 Error: " & @error) ;~ EndIf _ArrayConcatenate($carsDriveTrain, $carsDriveTrain2) _ArrayDisplay($carsDriveTrain, "Drive Train After Concat") ElseIf $driveTrainVal = "" Then _ArrayConcatenate($carsDriveTrain, $carsEngine) Else $carsDriveTrain = _filter($carsEngine, 0, 9, $driveTrain) EndIf Dim $carsOdom[1][16] $min = GUICtrlRead($odomMin) $max = GUICtrlRead($odomMax) For $i = 0 To UBound($carsDriveTrain) - 1 If $carsDriveTrain[$i][14] > $min And $carsDriveTrain[$i][14] < $max Then _ArrayAdd($carsOdom, $carsDriveTrain[$i]) MsgBox("", "", "ADDED!") EndIf Next _ArrayDisplay($carsOdom, "Cars Odom") $j += 1 WEnd _IEQuit($oIE) EndFunc ;==>_query Func _filter($tofilter, $xpos1, $ypos1, $str) ;~ If UBound($tofilter, 1) <= 1 Then ;~ $endx = 0 ;~ Else ;~ $endx = UBound($tofilter, 1) - 1 ;~ EndIf ;~ $cars = _ArrayFindAll($tofilter, $str, $tofilter[$xpos1][$ypos1], $tofilter[$endx][$ypos1], 0, 1, $ypos1, False) $cars = _ArrayFindAll($tofilter, $str, Default, Default, 0, 1, $ypos1) Dim $carsFiltered[1][16] = [["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p"]] ;_ArrayDisplay($carsFiltered) $i = 0 $uBound = UBound($cars) - 1 While $i < $uBound $filtered = _ArrayExtract($tofilter, $cars[$i], $cars[$i], 0, 15) ;_ArrayDisplay($filtered, "_filter Array of Filtered") _ArrayConcatenate($carsFiltered, $filtered) $i += 1 WEnd _ArrayDelete($carsFiltered, 0) Return $carsFiltered EndFunc ;==>_filter  
      If you know of a more efficient way of doing this please let me know would be more than happy to chew down my inefficiency while learning! (It's like my grandpa used to say, "The only criticism I can't use is that which is not given to me.")
       
      The Item an I am using to test the filter is:

       
    • rm4453
      By rm4453
      Hello,
       
      I am currently writing a program that parses a massive table from a website, and need a way to add a progress bar while parsing.
      I am currently using the function _IETableWriteToArray($oObj, True) to parse the array. I need the progress bar to update as the table is parsed, not just at the end of the parsing.
      Any help at all would be very much appreciated!
       
      *EDIT --> The array I am left with after parsing is $array[0-50000][16]
    • TrashBoat
      By TrashBoat
      So Im trying to make a simple 2d game and make some sort of collision detection so why not to make a 2 dimensional array but i have no clue how  to write it in multiple lines
      Global $map[5,5] = [0,0,0,0,0 _ [0,0,0,0,0 _ [0,0,0,0,0 _ [0,0,0,0,0 _ [0,0,0,0,0] something like this but it doesn't work
    • Zein
      By Zein
      #include "..\Include\Array.au3" #include "..\Include\File.au3" #include "..\Include\AutoItConstants.au3" Local $aRetArray Local $sFilePath = "n.csv" _FileReadToArray($sFilePath, $aRetArray, ",") ; _FileReadToArray($sFilePath, $aRetArray, $FRTA_COUNT, ",") _ArrayDisplay($aRetArray, "Original", Default, 8) The above code shows two versions of _FileReadToArray and both don't work as expected.
      The first one doesn't use the comma as a delimiter. (so I get a single column array)  I tried adding "Default" between $aRetArray and "," then it told me it had an incorrect number of parameters. 

      I looked again at the documentation:
       
      #include <File.au3> _FileReadToArray ( $sFilePath, ByRef $vReturn [, $iFlags = $FRTA_COUNT [, $sDelimiter = ""]] )
      And I with or without the flags params I should be getting a 2D array due to my file being a csv. 
      I then tried a regular flag, $FRTA_COUNT, and it tells me that I'm using a variable $FRTA_COUNT while it's not declared. Tried putting in 1 instead and it told me again, incorrect number of params. 

       
    • ternal
      By ternal
      Hi,
      Recently I have had the need to do a sort and then do a second sort while the item of the first sort stays the same ( double sorting , first on column x then while column x is the same sort column y).
      I did not put much efffort into error checking but so far I did not need it.
      For my applications so far it works perfectly however if someone is willing I want to test this extensivly.
      If anyone has big lists of random stuff to sort could you try this out please?
      #include <Array.au3> ; #FUNCTION# ==================================================================================================================== ; Name ..........: _ArraySort_Double ; Description ...: ; Syntax ........: _ArraySort_Double (Byref $array[, $first_index = Default[, $second_index = Default[, $ascending = Default]]]) ; Parameters ....: $array - 2d array to sort. ; $first_index - [optional] first column to sort. Default is 0. ; $second_index - [optional] second column to sort. Default is 1. ; $ascending - [optional] ascending/descending. Default is 1. ; Return values .: 1 if no errors occured , -1 if errors occured ; Author ........: Ternal ; Remarks .......: Needs excessive testing. ; Related .......: _arraysort() ; =============================================================================================================================== Func _ArraySort_Double (byref $array, $first_index = Default, $second_index = Default, $ascending = Default) Local $temp_value Local $counter = 1 If UBound($array, $UBOUND_DIMENSIONS) <> 2 Then MsgBox(0, "error", "error") return -1 EndIf If $first_index = Default Then $first_index = 0 If $second_index = Default Then $second_index = 1 If $ascending = Default Then $ascending = 1 _ArraySort($array, $ascending, 0, 0, $first_index); you can alter settings of primary sort here If @error Then MsgBox(0, "error", @error) return -1 EndIf $temp_value = $array[0][$first_index] For $x = 1 to UBound($array, 1) - 1 If Mod( $x, 10000) = 0 Then ConsoleWrite("at " & $x & " of a total : " & UBound($array, 1) & @CRLF) If $array[$x][$first_index] = $temp_value Then $counter+= 1 If $x = UBound($array, 1) - 1 Then; do last line here(if last line is not a new item) _ArraySort($array, $ascending, $x - $counter, $x, $second_index);you can alter settings of secondary sort here(don't forget to place line 34 the exact same) If @error Then MsgBox(0, "error", @error) return -1 EndIf EndIf Else If $counter > 0 Then ;at least 2 of the same _ArraySort($array, $ascending, $x - $counter, $x - 1, $second_index);you can alter settings of secondary sort here(don't forget to place line 29 the exact same) If @error Then MsgBox(0, "error", @error) return -1 EndIf $counter = 1 EndIf EndIf $temp_value = $array[$x][$first_index] Next Return 1 EndFunc Kind regards, Ternal
×