Page 1 of 1

Delete Object key - How?

Posted: 19 Jun 2019, 12:33
by Albireo
I have a string that I create an array from. (like this) .:

Code: Select all

InputCSV = 
( LTrim
	`n
	"201","Freddy","4,50"
	"302","Emelie","174,50"
	"203","Clas","9,90"
	
	"904","Johanna","1400,00"
	"205","Erica","1,75"
	
)
InputData := StrSplit(InputCSV, "`n")

MsgBox ,, Row %A_LineNumber% -> %A_ScriptName%, % InputCSV "`n`n" InputData.Count() "`n- " InputData[1] "`n- " InputData[2] "`n- " InputData[3] "`n- " InputData[4] "`n- " InputData[5] "`n- " InputData[6]
Count = 0
Loop % InputData.Count()
{	If ( StrLen(InputData[A_Index]) < 1 )
		InputData.Delete(A_Index)
	else
		Count += 1
}
MsgBox ,, Rad %A_LineNumber% -> %A_ScriptName%, % InputCSV "`n`n" InputData.Count() "`n- " InputData[1] "`n- " InputData[2] "`n- " InputData[3] "`n- " InputData[4] "`n- " InputData[5] "`n- " InputData[6]
There are empty rows in that string above (InputCSV). These should be deleted - along with the object keys.
But… InputData[1] is empty before InputData.Delete(1) and even after - why?
InputData.Count() is "9" before InputData.Delete() and "5" after (it's correct)

I have made an attempt with what I believe the AHK manual say about Object.delete()
But it doesn't work, as I want.
How can this be solved?

Re: Delete Object key - How?  Topic is solved

Posted: 19 Jun 2019, 12:48
by Hellbent
Is this what you're trying to do?

Code: Select all

Index:=InputData.Length()
Loop,% InputData.Length()	{
	If( StrLen(InputData[Index]) < 1 )
		InputData.RemoveAt(Index)
	
	Index--
}
Or if you want to save space.

Code: Select all

Loop,% Index:=InputData.Length()
	(StrLen(InputData[Index])< 1)?(InputData.RemoveAt(Index--)):(Index--)

Re: Delete Object key - How?

Posted: 19 Jun 2019, 13:41
by Albireo
Thank you!
Hellbent wrote:
19 Jun 2019, 12:48
... Or if you want to save space...
Save Space? (In the array or AHK-program?)
I get the result I want, in both examples.

What does this instruction do? Index--?

Re: Delete Object key - How?

Posted: 19 Jun 2019, 14:20
by Hellbent
Albireo wrote:
19 Jun 2019, 13:41
Thank you!
No problem.

Albireo wrote:
19 Jun 2019, 13:41
Hellbent wrote:
19 Jun 2019, 12:48
... Or if you want to save space...
Save Space? (In the array or AHK-program?)
I get the result I want, in both examples.
Just reduce the number of lines of code.
If it didn't add that in someone else would surly be along shortly to do it lol.

Albireo wrote:
19 Jun 2019, 13:41
What does this instruction do? Index--?
That is so that I can loop through the array backwards.
If you don't, when you remove a element, the one ahead of it gets shifted and fills that now vacant spot and ends up getting missed.

Re: Delete Object key - How?

Posted: 20 Jun 2019, 04:21
by just me
If you don't want to store empty lines in the array, don't store them:

Code: Select all

#NoEnv
InputCSV =
(LTrim
	`n
	"201","Freddy","4,50"
	"302","Emelie","174,50"
	"203","Clas","9,90"

	"904","Johanna","1400,00"
	"205","Erica","1,75"

)

; --------------------------------------
InputData := []
DataIndex := 0
For LineIndex, Line In StrSplit(InputCSV, "`n")
{
   LineCount := LineIndex
   If StrLen(Line)
   {
      DataIndex += 1
      InputData[DataIndex] := Line
   }
}
; --------------------------------------

DataLines := ""
For Each, Line In InputData
   DataLines .= "`n" Line
MsgBox ,, Row %A_LineNumber% -> %A_ScriptName%, % LineCount . "`n" . InputCSV . "`n`n`n" . InputData.Count() . DataLines

Re: Delete Object key - How?

Posted: 20 Jun 2019, 16:20
by Albireo
Thanks for the suggestion. All tips give the same results
Have done an analysis on all three examples.
I can't find any difference in performance with the suggestions from @Hellbent

Two CSV-files are used in the test,
- File1 with 25,622 rows (20 columns and 6172kB) and
- File2 with 34,658 rows (72 columns 6638kB)

The test was done as follows:
- Start the clock
- Load a CSV file
- Create an array
- Stop the clock


The result .: File1.: File2.:
@Helbent .: (94ms) (125ms)
@just me .: (2937ms) (3297ms)

Was very surprised that there was such a big difference.
I don't understand why!

Re: Delete Object key - How?

Posted: 20 Jun 2019, 16:31
by just me
The test was done as follows:
- Start the clock
- Load a CSV file
- Create an array
- Stop the clock

...
Was very surprised that there was such a big difference.
I don't understand why!
Nice, but I'm not able to run your 'script'. So I cannot help you.

Re: Delete Object key - How?

Posted: 20 Jun 2019, 18:59
by swagfag
reserve enough capacity for the array to hold 35k rows
push into the array with .Push, not via array index access
if strlen(line) to check whether a line is empty(assuming that was the intention) is wasteful

Re: Delete Object key - How?

Posted: 21 Jun 2019, 00:54
by SpeedMaster
Albireo wrote:
20 Jun 2019, 16:20
Have done an analysis on all three examples.
How about this one ? :think:

Code: Select all

Loop, % InputData.Length()
	(z:=InputData.Pop()) ? (InputData.InsertAt(1,z))

Re: Delete Object key - How?

Posted: 21 Jun 2019, 03:37
by Albireo
swagfag wrote:
20 Jun 2019, 18:59
reserve enough capacity for the array to hold 35k rows...
How do you do it? Something like that? InputData.SetCapacity(35000)
swagfag wrote:
20 Jun 2019, 18:59
...push into the array with .Push, not via array index access
if strlen(line) to check whether a line is empty(assuming that was the intention) is wasteful.
If you do not use StrLen(),how do you know which line is "empty"?
(Even a line that contains only field delimiters is empty and should be removed.)

The suggestion from @SpeedMaster give the following run times .:
File1 .: 3391ms
File2 .: 6313ms

Re: Delete Object key - How?

Posted: 21 Jun 2019, 04:06
by just me
Your benchmarking results are less meaningful if you don't show your complete benchmark script.

Re: Delete Object key - How?

Posted: 21 Jun 2019, 04:12
by swagfag
an empty line is "". anything else is by definition not empty. if u have redefined empty to mean something else, then simply checking against "" won't work. a different discriminator is required.

Re: Delete Object key - How?

Posted: 21 Jun 2019, 04:47
by just me
I just ran my own benchmark. Reading a CSV file with ~20000 rows of 18 columns (~3 MB) and converting it to an array using my code needs < 100 ms here.

Re: Delete Object key - How?

Posted: 21 Jun 2019, 18:25
by Albireo
Below is the AHK code I used.
To perform the tests I chose the input file, and configured Goto to different test codes

Unfortunately, I will not share the test files, but create your own files. The time differences will also depend on the type of computer the test takes place.

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
#Persistent
#SingleInstance Force
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

StartTime := A_TickCount
; FileRead InputCSV, c:\temp\FDT_ART_100.txt	; File1
FileRead InputCSV, c:\temp\EXPOART.txt		; File2

Goto Example4	; Example 1-4
ExitApp

Example1:	; Test1 @Helbent
	InputData := StrSplit(InputCSV, "`n")
	Loop % Index := InputData.Length()
		( StrLen(InputData[Index]) < 1 )?(InputData.RemoveAt(Index--)):(Index--)

	StopTime := A_TickCount
	CountTime := StopTime - StartTime
	MsgBox ,, Row %A_LineNumber% -> %A_ScriptName%, % "Ex1 `nNumber of rows .: " InputData.Count()"`nRunTime .: " CountTime " ms"
ExitApp


Example2:	; Test @Helbent
	InputData := StrSplit(InputCSV, "`n")
	Index:=InputData.Length()
	Loop,% InputData.Length()	{
		If( StrLen(InputData[Index]) < 1 )
			InputData.RemoveAt(Index)
	Index--
	}
	
	StopTime := A_TickCount
	CountTime := StopTime - StartTime
	MsgBox ,, Row %A_LineNumber% -> %A_ScriptName%, % "Ex2 `nNumber of rows .: " InputData.Count()"`nRunTime .: " CountTime " ms"
ExitApp


Example3:	; Test @just me
	InputData := []
	DataIndex := 0
	For LineIndex, Line In StrSplit(InputCSV, "`n")
	{	LineCount := LineIndex
		If StrLen(Line)
		{	DataIndex += 1
			InputData[DataIndex] := Line
		}
	}
	DataLines := ""
	For Each, Line In InputData
		DataLines .= "`n" Line
	
	StopTime := A_TickCount
	CountTime := StopTime - StartTime
	MsgBox ,, Row %A_LineNumber% -> %A_ScriptName%, % "Ex3 `nNumber of rows .: " InputData.Count()"`nRunTime .: " CountTime " ms"
ExitApp


Example4:	; Test @SpeedMaster
	InputData := StrSplit(InputCSV, "`n")
	Loop, % InputData.Length()
		(z:=InputData.Pop()) ? (InputData.InsertAt(1,z))

	StopTime := A_TickCount
	CountTime := StopTime - StartTime
	MsgBox ,, Row %A_LineNumber% -> %A_ScriptName%, % "Ex4 `nNumber of rows .: " InputData.Count()"`nRunTime .: " CountTime " ms"
ExitApp

Re: Delete Object key - How?

Posted: 21 Jun 2019, 19:04
by Hellbent
Albireo wrote:
21 Jun 2019, 18:25
Below is the AHK code I used.
To perform the tests I chose the input file, and configured Goto to different test codes
I ran your test. Here is my script.

Code: Select all

/*

#SingleInstance,Force
SetBatchLines,-1
FileDelete,%A_ScriptDir%\Test File.txt
temp:=""
Loop, 10000	{
	if(Mod(A_Index,4)=0){
		temp.= "`n"
	}else	{
		Temp .= "Some Random Text`n"
		
	}

}
FileAppend,%Temp%,%A_ScriptDir%\Test File.txt
SoundBeep, 500
return
*ESC::ExitApp

*/


#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
#Persistent
#SingleInstance Force
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

StartTime := A_TickCount
; FileRead InputCSV, c:\temp\FDT_ART_100.txt	; File1
FileRead InputCSV, %A_ScriptDir%\Test File.txt		; File2

Goto Example4	; Example 1-4     ;<--------- ran each 10 times to get fastest and longest times
ExitApp

Example1:	; Test1 @Helbent   ;<-------------------- 31 - 63 ms
	InputData := StrSplit(InputCSV, "`n")
	Loop % Index := InputData.Length()
		( StrLen(InputData[Index]) < 1 )?(InputData.RemoveAt(Index--)):(Index--)

	StopTime := A_TickCount
	CountTime := StopTime - StartTime
	MsgBox ,, Row %A_LineNumber% -> %A_ScriptName%, % "Ex1 `nNumber of rows .: " InputData.Count()"`nRunTime .: " CountTime " ms"
ExitApp


Example2:	; Test @Helbent    ;<-------------------- 31 - 93 ms
	InputData := StrSplit(InputCSV, "`n")
	Index:=InputData.Length()
	Loop,% InputData.Length()	{
		If( StrLen(InputData[Index]) < 1 )
			InputData.RemoveAt(Index)
	Index--
	}
	
	StopTime := A_TickCount
	CountTime := StopTime - StartTime
	MsgBox ,, Row %A_LineNumber% -> %A_ScriptName%, % "Ex2 `nNumber of rows .: " InputData.Count()"`nRunTime .: " CountTime " ms"
ExitApp


Example3:	; Test @just me       ;<-------------------- 125 - 157 ms
	InputData := []
	DataIndex := 0
	For LineIndex, Line In StrSplit(InputCSV, "`n")
	{	LineCount := LineIndex
		If StrLen(Line)
		{	DataIndex += 1
			InputData[DataIndex] := Line
		}
	}
	DataLines := ""
	For Each, Line In InputData
		DataLines .= "`n" Line
	
	StopTime := A_TickCount
	CountTime := StopTime - StartTime
	MsgBox ,, Row %A_LineNumber% -> %A_ScriptName%, % "Ex3 `nNumber of rows .: " InputData.Count()"`nRunTime .: " CountTime " ms"
ExitApp


Example4:	; Test @SpeedMaster     ;<-------------------- 1938 - 2063    ms
	InputData := StrSplit(InputCSV, "`n")
	Loop, % InputData.Length()
		(z:=InputData.Pop()) ? (InputData.InsertAt(1,z))

	StopTime := A_TickCount
	CountTime := StopTime - StartTime
	MsgBox ,, Row %A_LineNumber% -> %A_ScriptName%, % "Ex4 `nNumber of rows .: " InputData.Count()"`nRunTime .: " CountTime " ms"
ExitApp


I ran each one 10 times and recorded the fastest and slowest times.


Example 1: 31 - 63 ms
Example 2: 31 - 93 ms
Example 3: 125 - 157 ms
Example 4: 1938 - 2063 ms

***Edit***
Closer inspection of the strlen showed that min length was 1.

New results:
Example 1: average 250 ms
Example 2: average 250 ms
Example 3: average 125 ms

Re: Delete Object key - How?

Posted: 22 Jun 2019, 03:44
by just me
@Albireo:

Code: Select all

Example3:	; Test just me
	InputData := []
	DataIndex := 0
	For LineIndex, Line In StrSplit(InputCSV, "`n")
	{	LineCount := LineIndex
		If StrLen(Line)
		{	DataIndex += 1
			InputData[DataIndex] := Line
		}
	}
	DataLines := ""
	For Each, Line In InputData
		DataLines .= "`n" Line

	StopTime := A_TickCount
	CountTime := StopTime - StartTime
	MsgBox ,, Row %A_LineNumber% -> %A_ScriptName%, % "Ex3 `nNumber of rows .: " InputData.Count()"`nRunTime .: " CountTime " ms"
ExitApp
You kept the test code rebuilding a string from the array.

Code: Select all

	DataLines := ""
	For Each, Line In InputData
		DataLines .= "`n" Line
It consumes most of the time if the string gets really large.

Re: Delete Object key - How?

Posted: 22 Jun 2019, 05:13
by Albireo
swagfag wrote:
21 Jun 2019, 04:12
an empty line is "". anything else is by definition not empty. if u have redefined empty to mean something else, then simply checking against "" won't work. a different discriminator is required.
I agree with you, but in my world even a row with only field dividers can be empty. These "empty" lines occur when a tab with data in Excel, OpenOffice calc / LibreOffice calc, is processed with formulas into another tab and this tab is exported to a file with CSV structure.
All cells that lack content in the first tab will be empty cells in the second tab and only the field delimiters is exported for this rows.

e.g. Tab 1 contains 3 columns and 200 rows of data. Tab 2 retrieves data from Flik1 with formulas and performs something.
But in Tab 2, there are 500 rows of formulas (with data from Tab 1).
When Tab 2 is exported to a CSV file, the first 200 rows will contain data, while the 300 following rows will only contain field separators. The same thing happens if empty rows are inserted in the data on Tab 1
Because this happens quite often to me, I see these lines as empty and should be handled and skipped in the CSV-file, when the file is read by AHK.

Re: Delete Object key - How?

Posted: 22 Jun 2019, 05:55
by swagfag

Code: Select all

Cleaned := []
Cleaned.SetCapacity(BIG NUMBER)
emptyLineOrJustCommas := "^(?:,*)$"

Loop Parse, csvFile, `n
{
	if !(A_LoopField ~= emptyLineOrJustCommas)
		Cleaned.Push(A_LoopField)
}

Re: Delete Object key - How?

Posted: 30 Jun 2019, 05:23
by Albireo
swagfag wrote:
22 Jun 2019, 05:55

Code: Select all

Cleaned := []
Cleaned.SetCapacity(BIG NUMBER)
emptyLineOrJustCommas := "^(?:,*)$"

Loop Parse, csvFile, `n
{
	if !(A_LoopField ~= emptyLineOrJustCommas)
		Cleaned.Push(A_LoopField)
}
Thanks for your tip, but I don't understand what happens :?
Specially on line .: emptyLineOrJustCommas := "^(?:,*)$" and maybe if !(A_LoopField ~= emptyLineOrJustCommas)

If I understand correctly, all rows that are empty or just consist of "," (comma) are ignored
But how to control other separators? (like ";" "TAB" or ...)?
Can these be checked in the same code?