supersonic Posted July 1, 2009 Posted July 1, 2009 (edited) Hi! Is there already a build-in function to remove empty rows in a 2D array? _ArrayUnique wouldn't help, because it's only for 1D arrays. Sure, i could write an UDF like this: #include <Array.au3> Dim $aTmp[5][5] = [[0, 1], [2, 3], ["", ""], ["", ""], [4, 5]] _ArrayDisplay($aTmp, "$aTmp_BEFORE") _Array2DDeleteEmptyRows($aTmp) _ArrayDisplay($aTmp, "$aTmp_AFTER") Func _Array2DDeleteEmptyRows(ByRef $iArray) Local $vEmpty = True For $i = UBound($iArray, 2) - 1 To 0 Step -1 For $j = 0 To UBound($iArray, 1) - 1 Step 1 If StringCompare($iArray[$i][$j], "", 0) <> 0 Then $vEmpty = False EndIf Next If $vEmpty = True Then _ArrayDelete($iArray, $i) $vEmpty = True Next EndFunc But when targeting rather huge arrays (> 1000) this UDF will be slow. Any ideas? Greets, -supersonic. Edited July 1, 2009 by supersonic
supersonic Posted July 1, 2009 Author Posted July 1, 2009 I updated the script; maybe someone could produce fast code? Hi! Is there already a build-in function to remove empty rows in a 2D array? _ArrayUnique wouldn't help, because it's only for 1D arrays. Sure, i could write an UDF like this: #include <Array.au3> Dim $aTmp[5][5] = [[0, 1], [2, 3], ["", ""], ["", ""], [4, 5]] _ArrayDisplay($aTmp, "$aTmp_BEFORE") _Array2DDeleteEmptyRows($aTmp) _ArrayDisplay($aTmp, "$aTmp_AFTER") Func _Array2DDeleteEmptyRows(ByRef $iArray) Local $vEmpty = True For $i = UBound($iArray, 2) - 1 To 0 Step -1 For $j = 0 To UBound($iArray, 1) - 1 Step 1 If StringCompare($iArray[$i][$j], "", 0) <> 0 Then $vEmpty = False EndIf Next If $vEmpty = True Then _ArrayDelete($iArray, $i) $vEmpty = True Next EndFunc But when targeting rather huge arrays (> 1000) this UDF will be slow. Any ideas? Greets, -supersonic.
weaponx Posted July 1, 2009 Posted July 1, 2009 Why are using StringCompare instead of just checking if the element equals "" ?
supersonic Posted July 1, 2009 Author Posted July 1, 2009 Why are using StringCompare instead of just checking if the element equals "" ? You're right, I've changed the UDF: Func _Array2DDeleteEmptyRows(ByRef $iArray) Local $vEmpty = True If IsArray($iArray) = 1 And UBound($iArray, 2) - 1 > -1 Then For $i = UBound($iArray, 2) - 1 To 0 Step -1 For $j = 0 To UBound($iArray, 1) - 1 Step 1 If $iArray[$i][$j] <> "" Then $vEmpty = False Next If $vEmpty = True Then _ArrayDelete($iArray, $i) $vEmpty = True Next Else SetError(1, 0, 0) EndIf EndFunc But it's still slow...
weaponx Posted July 1, 2009 Posted July 1, 2009 (edited) Try this. Yours took 486 ms and I got it down to 30 ms. expandcollapse popup#include <Array.au3> Dim $aTmp[1000][2] ;Fill array with junk For $X = 0 to 999 ;Insert empty element every 10 nodes, fill the rest with junk If Mod($X,10) = 0 Then $aTmp[$X][0] = "" $aTmp[$X][1] = "" Else $aTmp[$X][0] = "ebgrhrrtbnwrbnwfg" $aTmp[$X][1] = "bwefwergethcbrtgh" EndIf Next _ArrayDisplay($aTmp, "$aTmp_BEFORE") $T1 = TimerInit() ;_Array2DDeleteEmptyRows($aTmp) $aTmp = _DeleteEmptyRows($aTmp) ConsoleWrite("T1: " & TimerDiff($T1) & @CRLF) _ArrayDisplay($aTmp, "$aTmp_AFTER") ;486 ms Func _Array2DDeleteEmptyRows(ByRef $iArray) Local $vEmpty = True For $i = UBound($iArray) - 1 To 0 Step -1 For $j = 0 To UBound($iArray, 2)-1 Step 1 If $iArray[$i][$j] <> "" Then $vEmpty = False EndIf Next If $vEmpty = True Then _ArrayDelete($iArray, $i) $vEmpty = True Next EndFunc ;30 ms Func _DeleteEmptyRows($aArray) Local $Rows = Ubound($aArray,1) Local $Cols = Ubound($aArray,2) Local $aTemp[$Rows][$Cols] Local $not_empty Local $Count = 0 ;Loop through rows For $Y = 0 to $Rows - 1 $not_empty = 0 ;Loop through columns For $X = 0 to $Cols - 1 ;Copy all columns to temp array even if they are all empty $aTemp[$Count][$X] = $aArray[$Y][$X] ;If even one column contains data, make sure it doesn't get deleted If $aArray[$Y][$X] <> "" Then $not_empty = BitOr($not_empty, 1) Next ;If the row has any data, increment, else keep overwriting last row until it contains something If $not_empty Then $Count += 1 Next Redim $aTemp[$Count][$Cols] Return $aTemp EndFunc Edited July 1, 2009 by weaponx AnonymousX 1
supersonic Posted July 1, 2009 Author Posted July 1, 2009 Thanks for your help! Maybe UBound() in the second For-loop slows down my UDF. Try this. Yours took 486 ms and I got it down to 30 ms. expandcollapse popup#include <Array.au3> Dim $aTmp[1000][2] ;Fill array with junk For $X = 0 to 999 ;Insert empty element every 10 nodes, fill the rest with junk If Mod($X,10) = 0 Then $aTmp[$X][0] = "" $aTmp[$X][1] = "" Else $aTmp[$X][0] = "ebgrhrrtbnwrbnwfg" $aTmp[$X][1] = "bwefwergethcbrtgh" EndIf Next _ArrayDisplay($aTmp, "$aTmp_BEFORE") $T1 = TimerInit() ;_Array2DDeleteEmptyRows($aTmp) $aTmp = _DeleteEmptyRows($aTmp) ConsoleWrite("T1: " & TimerDiff($T1) & @CRLF) _ArrayDisplay($aTmp, "$aTmp_AFTER") ;486 ms Func _Array2DDeleteEmptyRows(ByRef $iArray) Local $vEmpty = True For $i = UBound($iArray) - 1 To 0 Step -1 For $j = 0 To UBound($iArray, 2)-1 Step 1 If $iArray[$i][$j] <> "" Then $vEmpty = False EndIf Next If $vEmpty = True Then _ArrayDelete($iArray, $i) $vEmpty = True Next EndFunc ;30 ms Func _DeleteEmptyRows($aArray) Local $Rows = Ubound($aArray,1) Local $Cols = Ubound($aArray,2) Local $aTemp[$Rows][$Cols] Local $not_empty Local $Count = 0 ;Loop through rows For $Y = 0 to $Rows - 1 $not_empty = 0 ;Loop through columns For $X = 0 to $Cols - 1 ;Copy all columns to temp array even if they are all empty $aTemp[$Count][$X] = $aArray[$Y][$X] ;If even one column contains data, make sure it doesn't get deleted If $aArray[$Y][$X] <> "" Then $not_empty = BitOr($not_empty, 1) Next ;If the row has any data, increment, else keep overwriting last row until it contains something If $not_empty Then $Count += 1 Next Redim $aTemp[$Count][$Cols] Return $aTemp EndFunc
weaponx Posted July 1, 2009 Posted July 1, 2009 Thanks for your help! Maybe UBound() in the second For-loop slows down my UDF.No. _ArrayDelete is the slow part. AnonymousX 1
wolf9228 Posted July 1, 2009 Posted July 1, 2009 (edited) Hi! Is there already a build-in function to remove empty rows in a 2D array? _ArrayUnique wouldn't help, because it's only for 1D arrays. Sure, i could write an UDF like this: #include <Array.au3> Dim $aTmp[5][5] = [[0, 1], [2, 3], ["", ""], ["", ""], [4, 5]] _ArrayDisplay($aTmp, "$aTmp_BEFORE") _Array2DDeleteEmptyRows($aTmp) _ArrayDisplay($aTmp, "$aTmp_AFTER") Func _Array2DDeleteEmptyRows(ByRef $iArray) Local $vEmpty = True For $i = UBound($iArray, 2) - 1 To 0 Step -1 For $j = 0 To UBound($iArray, 1) - 1 Step 1 If StringCompare($iArray[$i][$j], "", 0) <> 0 Then $vEmpty = False EndIf Next If $vEmpty = True Then _ArrayDelete($iArray, $i) $vEmpty = True Next EndFunc Sorry there is an error in this code, I reform This code right #include <Array.au3> Dim $aTmp[5][5] = [[0, 1], [2, 3], ["", ""], ["", ""], [4, 5]] _ArrayDisplay($aTmp, "$aTmp_BEFORE") $iArrayOut = _Array2DDeleteEmptyRows($aTmp) _ArrayDisplay($iArrayOut, "$aTmp_AFTER") Func _Array2DDeleteEmptyRows(ByRef $iArray) Local $vEmpty = False $cols = UBound($iArray, 2) Local $iArrayOut[1][$cols] , $A = 0 For $i = 0 To (UBound($iArray, 1) - 1) Step 1 if $vEmpty = True Then $A += 1 $vEmpty = False For $j = 0 To (UBound($iArray, 2) - 1) Step 1 If StringCompare($iArray[$i][$j], "", 0) <> 0 Then ReDim $iArrayOut[$A + 1][$cols] $iArrayOut[$A][$j] = $iArray[$i][$j] $vEmpty = True EndIf Next Next Return $iArrayOut EndFunc Edited July 1, 2009 by wolf9228 صرح السماء كان هنا
weaponx Posted July 1, 2009 Posted July 1, 2009 #include <Array.au3> Dim $aTmp[5][5] = [[0, 1], [2, 3], ["", ""], ["", ""], [4, 5]] _ArrayDisplay($aTmp, "$aTmp_BEFORE") _Array2DDeleteEmptyRows($aTmp) _ArrayDisplay($aTmp, "$aTmp_AFTER") MsgBox(0,"",$aTmp[0][0]) Func _Array2DDeleteEmptyRows(ByRef $iArray) Local $vEmpty = False $cols = UBound($iArray, 2) Local $iArrayOut[1][$cols] , $A = 0 For $i = 0 To (UBound($iArray, 1) - 1) Step 1 if $vEmpty = True Then $A += 1 $vEmpty = False For $j = 0 To (UBound($iArray, 2) - 1) Step 1 If StringCompare($iArray[$i][$j], "", 0) <> 0 Then ReDim $iArrayOut[$A + 1][$cols] $iArrayOut[$A][$j] = $iArray[$i][$j] $vEmpty = True EndIf Next Next $iArray = $iArrayOut EndFunc That took longer than the one the OP posted originally! 1740 ms AnonymousX 1
AnonymousX Posted February 12, 2017 Posted February 12, 2017 On 7/1/2009 at 10:35 AM, weaponx said: Try this. Yours took 486 ms and I got it down to 30 ms. expandcollapse popup#include <Array.au3> Dim $aTmp[1000][2] ;Fill array with junk For $X = 0 to 999 ;Insert empty element every 10 nodes, fill the rest with junk If Mod($X,10) = 0 Then $aTmp[$X][0] = "" $aTmp[$X][1] = "" Else $aTmp[$X][0] = "ebgrhrrtbnwrbnwfg" $aTmp[$X][1] = "bwefwergethcbrtgh" EndIf Next _ArrayDisplay($aTmp, "$aTmp_BEFORE") $T1 = TimerInit() ;_Array2DDeleteEmptyRows($aTmp) $aTmp = _DeleteEmptyRows($aTmp) ConsoleWrite("T1: " & TimerDiff($T1) & @CRLF) _ArrayDisplay($aTmp, "$aTmp_AFTER") ;486 ms Func _Array2DDeleteEmptyRows(ByRef $iArray) Local $vEmpty = True For $i = UBound($iArray) - 1 To 0 Step -1 For $j = 0 To UBound($iArray, 2)-1 Step 1 If $iArray[$i][$j] <> "" Then $vEmpty = False EndIf Next If $vEmpty = True Then _ArrayDelete($iArray, $i) $vEmpty = True Next EndFunc ;30 ms Func _DeleteEmptyRows($aArray) Local $Rows = Ubound($aArray,1) Local $Cols = Ubound($aArray,2) Local $aTemp[$Rows][$Cols] Local $not_empty Local $Count = 0 ;Loop through rows For $Y = 0 to $Rows - 1 $not_empty = 0 ;Loop through columns For $X = 0 to $Cols - 1 ;Copy all columns to temp array even if they are all empty $aTemp[$Count][$X] = $aArray[$Y][$X] ;If even one column contains data, make sure it doesn't get deleted If $aArray[$Y][$X] <> "" Then $not_empty = BitOr($not_empty, 1) Next ;If the row has any data, increment, else keep overwriting last row until it contains something If $not_empty Then $Count += 1 Next Redim $aTemp[$Count][$Cols] Return $aTemp EndFunc Thanks weaponx, Still helping folks 8 years after posted! weaponx 1
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now