Modify

Opened 15 years ago

Closed 15 years ago

#1806 closed Bug (No Bug)

$iBase in _ArrayUnique() not working properly

Reported by: UEZ Owned by:
Milestone: Component: AutoIt
Version: 3.3.6.1 Severity: None
Keywords: _ArrayUnique() 0-base 1-base Cc:

Description

#include <Array.au3>
Dim $aArray[10] = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
_ArrayDisplay($aArray, "$aArray")
$aNewArray = _ArrayUnique($aArray, 1, 0) ;Using Default Parameters
_ArrayDisplay($aNewArray, "$aNewArray represents the 1st Dimension of $aArray")

Should return a 0 based array but it doesn't because of line 1414 in Array.au3
-=> $aArrayTmp = StringSplit(StringTrimRight($sHold, StringLen($vDelim)), $vDelim, 1) ;Split the string into an array

Is working with line:
-=> $aArrayTmp = StringSplit(StringTrimRight($sHold, StringLen($vDelim)), $vDelim, 2 - $iBase)
but a $iBase check needs to be implemented before to avoid any numbers outside 0,1!

Br,
UEZ

Attachments (0)

Change History (5)

comment:1 by UEZ, 15 years ago

Seems _ArrayUnique() is also not working properly with 2D arrays!

Br,
UEZ

comment:2 by UEZ, 15 years ago

Here my try for the ArrayUnique function for up to 2D arrays:

; #FUNCTION# ====================================================================================================================
; Name...........: ArrayUnique
; Description ...: Returns the Unique Elements of a 1-dimensional or 2-dimensional array.
; Syntax.........: _ArrayUnique($aArray[, $iBase = 0, oBase = 0, $iCase = 0])
; Parameters ....: $aArray - The Array to use
;                  $iBase  - [optional] Is the input Array 0-base or 1-base index.  0-base by default
;                  $oBase  - [optional] Is the output Array 0-base or 1-base index.  0-base by default
;                  $iCase  - [optional] Flag to indicate if the operations should be case sensitive.
;                  0 = not case sensitive, using the user's locale (default)
;                  1 = case sensitive
;                  2 = not case sensitive, using a basic/faster comparison
; Return values .: Success - Returns a 1-dimensional or 2-dimensional array containing only the unique elements of that Dimension
;                  Failure - Returns 0 and Sets @Error:
;                  0 - No error.
;                  1 - Returns 0 if parameter is not an array.
;                  2 - Array has more than 2 dimensions
;                  3 - Array is already unique
; Remarks .......: Needs the function Max()
; Author ........: UEZ 2010 for 2D-array, Eukalyptus for 1D-array (modified by AspirinJunkie)
; Version .......: 0.90 Build 2010-11-10 Beta
; ===============================================================================================================================
Func ArrayUnique($aArray, $iBase = 0, $oBase = 0, $iCase = 0)
	If Not IsArray($aArray) Then Return SetError(1, 0, 0) ;not an array
	If UBound($aArray, 0) > 2 Then Return SetError(2, 0, 0) ;array is greater than a 2D array
	If UBound($aArray) + $iBase = $iBase + 1 Then Return SetError(3, 0, $aArray) ;array is already unique
	Local $dim = UBound($aArray, 2), $i
	If $dim Then ;2D array
		Local $aUnique[2][$dim]
		Local $j, $k = $oBase, $sTemp, $sHold, $empty = 0
		For $i = $iBase To UBound($aArray) - 1
			For $j = 0 To $dim - 1
				If $aArray[$i][$j] <> "" Then
					$sTemp &= $aArray[$i][$j]
				Else
					$empty += 1
				EndIf
			Next
			If $empty < $dim Then $empty = 0

			If Not StringInStr($sHold, $sTemp, $iCase) And Not $empty Then
				$sHold &= $sTemp
				For $j = 0 To $dim - 1
					$aUnique[$k][$j] = $aArray[$i][$j]
				Next
				ReDim $aUnique[$k + 2][$dim]
				$k += 1
			EndIf
			$sTemp = ""
			$empty = 0
		Next
		ReDim $aUnique[UBound($aUnique) -1][$dim]
		If $oBase Then $aUnique[0][Max(UBound($aUnique, 0) - 2, 0)] = UBound($aUnique) - 1
	Else ;1D array
		Local Static $oD = ObjCreate('Scripting.Dictionary')
		For $i In $aArray
			If Not $oD.Exists($i) Then $oD.Add($i, 0)
		Next
		Local $aUnique = $oD.Keys()
		$oD.RemoveAll
	EndIf
	Return SetError(0, 0, $aUnique)
EndFunc

Func Max($a, $b)
	If $a > $b Then Return $a
	Return $b
EndFunc

I hope it is bug free ;-)

Br,
UEZ

comment:3 by anonymous, 15 years ago

Here an update of my ArrayUnique function (some bugs fixed):

; #FUNCTION# =====================================================================================================================
; Name...........: ArrayUnique
; Description ...: Returns the Unique Elements of a 1-dimensional or 2-dimensional array.
; Syntax.........: _ArrayUnique($aArray[, $iBase = 0, oBase = 0, $iCase = 0])
; Parameters ....: $aArray - The Array to use
;                  $iBase  - [optional] Is the input Array 0-base or 1-base index.  0-base by default
;                  $oBase  - [optional] Is the output Array 0-base or 1-base index.  0-base by default
;                  $iCase  - [optional] Flag to indicate if the operations should be case sensitive.
;                  0 = not case sensitive, using the user's locale (default)
;                  1 = case sensitive
;                  2 = not case sensitive, using a basic/faster comparison
; Return values .: Success - Returns a 1-dimensional or 2-dimensional array containing only the unique elements of that Dimension
;                  Failure - Returns 0 and Sets @Error:
;                  0 - No error.
;                  1 - Returns 0 if parameter is not an array.
;                  2 - Array has more than 2 dimensions
;                  3 - Array is already unique
;                  4 - Scripting.Dictionary cannot be created for 1D array unique code
; Remarks .......: Needs the function Max()
; Author ........: UEZ 2010 for 2D-array, Eukalyptus for 1D-array (modified by AspirinJunkie)
; Version .......: 0.91 Build 2010-11-11 Beta
; ================================================================================================================================
Func ArrayUnique($aArray, $iBase = 0, $oBase = 0, $iCase = 0)
	If Not IsArray($aArray) Then Return SetError(1, 0, 0) ;not an array
	If UBound($aArray, 0) > 2 Then Return SetError(2, 0, 0) ;array is greater than a 2D array
	If UBound($aArray) + $iBase = $iBase + 1 Then Return SetError(3, 0, $aArray) ;array is already unique
	Local $dim = UBound($aArray, 2), $i
	If $dim Then ;2D array
		Local $aUnique[2][$dim]
		Local $j, $k = $oBase, $sTemp, $sHold, $empty = 0
		For $i = $iBase To UBound($aArray) - 1
			For $j = 0 To $dim - 1
				If $aArray[$i][$j] <> "" Then
					$sTemp &= $aArray[$i][$j]
				Else
					$empty += 1
				EndIf
			Next
			If $empty < $dim Then $empty = 0
			$sTemp &= Chr(01)
			If Not StringInStr($sHold, $sTemp, $iCase) And Not $empty Then
				$sHold &= $sTemp
				For $j = 0 To $dim - 1
					$aUnique[$k][$j] = $aArray[$i][$j]
				Next
				ReDim $aUnique[$k + 2][$dim]
				$k += 1
			EndIf
			$sTemp = ""
			$empty = 0
		Next
		ReDim $aUnique[UBound($aUnique) -1][$dim]
		If $oBase Then $aUnique[0][Max(UBound($aUnique, 0) - 2, 0)] = UBound($aUnique) - 1
	Else ;1D array
		Local $oD = ObjCreate('Scripting.Dictionary')
		If @error Then Return SetError(4, 0, 0)
		For $i In $aArray
			If Not $oD.Exists($i) Then $oD.Add($i, 0)
		Next
		Local $aUnique = $oD.Keys()
		$oD.RemoveAll
	EndIf
	Return SetError(0, 0, $aUnique)
EndFunc

Func Max($a, $b)
	If $a > $b Then Return $a
	Return $b
EndFunc

Br,
UEZ

comment:4 by anonymous, 15 years ago

Here my latest version:

; #FUNCTION# ============================================================================
; Name.............: 	ArrayUnique
; Description ...: 	Returns the Unique Elements of a 1-dimensional or 2-dimensional array.
; Syntax...........: 	_ArrayUnique($aArray[, $iBase = 0, oBase = 0])
; Parameters ...: 	$aArray - The Array to use
;                  			$iBase  - [optional] Is the input Array 0-base or 1-base index.  0-base by default
;                  			$oBase  - [optional] Is the output Array 0-base or 1-base index.  0-base by default
; Return values:	Success - Returns a 1-dimensional or 2-dimensional array containing only the unique elements
;                  			Failure - Returns 0 and Sets @Error:
;                  			0 - No error.
;                  			1 - Returns 0 if parameter is not an array.
;                  			2 - Array has more than 2 dimensions
;                  			3 - Array is already unique
;                  			4 - when source array is selected as one base but UBound(array) - 1 <> array[0] / array[0][0]
;                  			5 - Scripting.Dictionary cannot be created for 1D array unique code
; Author .........: 	UEZ 2010 for 2D-array, Yashied for 1D-array (modified by UEZ)
; Version ........: 	0.96 Build 2010-11-20 Beta
; =======================================================================================
Func ArrayUnique($aArray, $iBase = 0, $oBase = 0)
	If Not IsArray($aArray) Then Return SetError(1, 0, 0) ;not an array
	If UBound($aArray, 0) > 2 Then Return SetError(2, 0, 0) ;array is greater than a 2D array
	If UBound($aArray) = $iBase + 1 Then Return SetError(3, 0, $aArray) ;array is already unique because of only 1 element
	Local $dim = UBound($aArray, 2), $i
	If $dim Then ;2D array
		If $iBase And UBound($aArray) - 1 <> $aArray[0][0] Then Return SetError(4, 0, 0)
		Local $oD = ObjCreate('Scripting.Dictionary')
		If @error Then Return SetError(5, 0, 0)
		Local $i, $j, $k = $oBase, $l, $s, $aTmp, $flag, $sSep = Chr(01)
		Local $aUnique[UBound($aArray)][$dim]
		If Not $oBase Then $flag = 2
        For $i =  $iBase To UBound($aArray) - 1
			For $j = 0 To $dim - 1
				$s &= $aArray[$i][$j] & $sSep
			Next
			If Not $oD.Exists($s) And StringLen($s) > 3 Then
				$oD.Add($s, $i)
				$aTmp = StringSplit(StringTrimRight($s, 1), $sSep, 2)
				For $l = 0 To $dim - 1
					$aUnique[$k][$l] = $aTmp[$l]
				Next
				$k += 1
			EndIf
			$s = ""
		Next
        $oD.RemoveAll
		$oD = ""
		If $k > 0 Then
			If $oBase Then $aUnique[0][0] = $k - 1
			ReDim $aUnique[$k][$dim]
		Else
			ReDim $aUnique[1][$dim]
		EndIf
	Else ;1D array
		If $iBase And UBound($aArray) - 1 <> $aArray[0] Then Return SetError(4, 0, 0)
		Local $sData = '', $sSep = ChrW(160), $flag
		For $i = $iBase To UBound($aArray) - 1
			If Not IsDeclared($aArray[$i] & '$') Then
				Assign($aArray[$i] & '$', 0, 1)
				$sData &= $aArray[$i] & $sSep
			EndIf
		Next
		If Not $oBase Then $flag = 2
		Local $aUnique = StringSplit(StringTrimRight($sData, 1), $sSep, $flag)
	EndIf
	Return SetError(0, 0, $aUnique)
EndFunc   ;==>ArrayUnique

Is this something for you?

Br,
UEZ

comment:5 by J-Paul Mesnage, 15 years ago

Resolution: No Bug
Status: newclosed

There is no error just use

Local $aArray[10] = [9, 2, 3, 4, 6, 1, 2, 3, 4, 6]

and play with the $iBase = 0 or 1

The remaining of the thread shoud go to a "new request" for 2D array support

Modify Ticket

Action
as closed The ticket will remain with no owner.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.