Modify

Opened 9 years ago

Closed 9 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 Changed 9 years ago by UEZ

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

Br,
UEZ

comment:2 Changed 9 years ago by UEZ

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 Changed 9 years ago by anonymous

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 Changed 9 years ago by anonymous

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 Changed 9 years ago by Jpm

  • Resolution set to No Bug
  • Status changed from new to closed

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

Guidelines for posting comments:

  • You cannot re-open a ticket but you may still leave a comment if you have additional information to add.
  • In-depth discussions should take place on the forum.

For more information see the full version of the ticket guidelines here.

Add Comment

Modify Ticket

Action
as closed The ticket will remain with no owner.
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.