_GetMinMaxNumber kleinsten, größten Wert aus Singlevariablen und/oder 1D-Arrays ermitteln

    • Offizieller Beitrag

    Hiermit lassen sich Min/Max -Werte aus bis zu 10 Einzelvariablen und/oder 1D-Arrays ermitteln. Die Werte können als echte 'Number' oder als Zahlenstring vorliegen. Nichtnumerische Werte und Nicht-Zahlenstrings werden ignoriert. Ausschließlich für den ersten Wert muß (sofern kein Array übergeben wird) zwingend ein Number/Zahlenstring übergeben werden, da dieser als erster Vergleichswert genutzt wird und nicht übergangen werden kann.
    Da Number() eine Funktionslücke aufweist, verwende ich die Funktion in Kombination mit einer eigenen IsNumber/Digit/Float -Prüfung.
    Um Parameter zu sparen, habe ich den Parameter für Array-StartIndex 'vergewaltigt', sodass ohne Vorzeichen die Funktion als MinNumber und mit '+' die Funktion als MaxNumber arbeitet. ;)

    Spoiler anzeigen
    [autoit]

    Local $a[5] = [3,2,8,78,9]
    Local $a1[1] = [-1]
    Local $a2[4] = [40,3,22,12]

    [/autoit] [autoit][/autoit] [autoit]

    ; === erster Parameter für Min und Startindex der Arrays ==> hier also: 0
    ConsoleWrite('Min: ' & _GetMinMaxNumber(0, $a2, 12, $a1, 5, 7, $a) & @CRLF)
    ; === erster Parameter für Max und Startindex der Arrays ==> hier also: '+0'
    ConsoleWrite('Max: ' & _GetMinMaxNumber('+0', $a2, 12, $a1, 5, 7, $a) & @CRLF & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ; === Arrays mit Startindex 1
    Local $a[5] = [4,56,78,23,47]
    Local $a1[3] = [2,352,-98]
    Local $a2[2] = [1,117]
    ConsoleWrite('Min: ' & _GetMinMaxNumber(1, $a, $a1, $a2) & @CRLF)
    ConsoleWrite('Max: ' & _GetMinMaxNumber('+1', $a, $a1, $a2) & @CRLF & @CRLF)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; === ohne Array ist erster Parameter nur für Wahl Min ('') oder Max ('+')
    ConsoleWrite('Min: ' & _GetMinMaxNumber('', '4', 8, 1+1+3, 12, '3.25', 5, 7, 'Text-String_wird_ignoriert') & @CRLF)
    ConsoleWrite('Max: ' & _GetMinMaxNumber('+', '4', 8, 1+1+3, 12, '3.25', 5, 7, 'Text-String_wird_ignoriert') & @CRLF)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _GetMinMaxNumber
    ; Description ...: Ermittelt den kleinsten Zahlenwert aus bis zu 10 übergebenen Einzelvariablen und/oder 1D-Arrays
    ; Syntax.........: _GetMinMaxNumber($sTypeIndx, $n1, $n2, $n3=Default, ... $n10=Default)
    ; Parameters ....: $sTypeIndx Start-Index übergebener Arrays mit Vorzeichen '+' für Rückgabe MaxNumber
    ; Für Rückgabe MinNumber braucht kein Vorzeichen übergeben werden.
    ; Werden keine Arrays verwendet, wird nur '+' für Max oder '' für Min übergeben.
    ; $n1...$n10 Einzelwerte und/oder 1D-Arrays
    ; Return values .: Erfolg kleinster/größter Zahlenwert aus allen Parametern
    ; Fehler Leerstring, @error: 1 ==> Einzelwert $n1 ist nicht numerisch
    ; Author ........: BugFix ( [email='bugfix@autoit.de'][/email] )
    ; Remarks .......: Bei Verwendung von Arrays gilt für alle derselbe Startindex.
    ; Ist $n1 kein Array, muß der Wert zwingend numerisch/Zahlenstring sein. Andere Werte
    ; (auch innerhalb übergebener Arrays) werden ignoriert, wenn sie nicht numerisch/Zahlenstring sind.
    ; Als String übergebene Zahlen (Ganzzahlen, Float) werden beim Vergleich zu Number gewandelt.
    ; ===============================================================================================================================
    Func _GetMinMaxNumber($sTypeIndx, $n1, $n2, $n3=Default, $n4=Default, $n5=Default, $n6=Default, $n7=Default, $n8=Default, $n9=Default, $n10=Default)
    Local $min_max = $n1, $min_max2, $val, $max = 0
    If StringLeft($sTypeIndx, 1) = '+' Then $max = 1
    If $n2 == 'sub' Then
    If UBound($n1) = $sTypeIndx +1 Then Return $n1[UBound($n1) -1]
    $min_max = $n1[$sTypeIndx]
    For $i = $sTypeIndx +1 To UBound($n1) -1
    If StringRegExp($n1[$i], '\A[-+]{0,1}\d+\.{0,1}\d*\z') Then
    $n1[$i] = Number($n1[$i])
    Else
    ContinueLoop
    EndIf
    If $max Then
    If $n1[$i] > $min_max Then $min_max = $n1[$i]
    Else
    If $n1[$i] < $min_max Then $min_max = $n1[$i]
    EndIf
    Next
    Return $min_max
    EndIf
    If IsArray($min_max) Then
    $min_max = _GetMinMaxNumber($sTypeIndx, $min_max, 'sub')
    Else
    If StringRegExp($min_max, '\A[-+]{0,1}\d+\.{0,1}\d*\z') Then
    $min_max = Number($min_max)
    Else
    Return SetError(1,0,'')
    EndIf
    EndIf
    For $i = 2 To 10
    $val = Eval('n' & $i)
    If IsKeyword($val) Then ExitLoop
    If IsArray($val) Then
    $min_max2 = _GetMinMaxNumber($sTypeIndx, $val, 'sub')
    If $max Then
    If $min_max2 > $min_max Then $min_max = $min_max2
    Else
    If $min_max2 < $min_max Then $min_max = $min_max2
    EndIf
    Else
    If StringRegExp($val, '\A[-+]{0,1}\d+\.{0,1}\d*\z') Then
    $val = Number($val)
    If $max Then
    If $val > $min_max Then $min_max = $val
    Else
    If $val < $min_max Then $min_max = $val
    EndIf
    EndIf
    EndIf
    Next
    Return $min_max
    EndFunc ;==>_GetMinMaxNumber

    [/autoit]
  • Warum hast du nicht das Ganze allgemein gehalten, also z.B. für die n größte bzw. kleinste Zahl? ;)

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    • Offizieller Beitrag

    Warum hast du nicht das Ganze allgemein gehalten, also z.B. für die n größte bzw. kleinste Zahl?

    Meinst du das jetzt in Bezug auf die Anzahl zu übergebender Parameter? - Die Anzahl ist ja nur dann 'unbegrenzt', wenn ich Werte in einem Array übergebe, dann kann ich wiederum nur eines (oder definierte Anzahl) übergeben.
    Falls du das auf die Funktion selbst beziehst (2 Funktionen in einer), so tat es mir einfach in der Seele weh, 2-mal absolut identische Funktionen zu schreiben, die sich nur durch Vergleichsoperatoren unterscheiden. Und das '+' zur Anwahl von Max halte ich für logisch nachvollziehbar. Es ist programmiertechnisch sicher nicht der edelste Stil - aber auch nicht unbedingt grottig. ;)

  • Eigentlich meine ich, dass du ein String oder ein Array übergibst und du z.B. die 7 größte oder 4 kleinste Zahl haben willst .

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    • Offizieller Beitrag
    Zitat

    Eigentlich meine ich, dass du ein String oder ein Array übergibst und du z.B. die 7 größte oder 4 kleinste Zahl haben willst .


    Klar läßt sich das machen, wäre aber eine völlig andere Aufgabenstellung.
    Hier wollte ich wirklich nur aus verschiedenen Quellen den kleinsten/größten Wert selektieren und das ohne extra Funktionen (wie _ArrayMin ..Max) zu bemühen.

    Edit:
    Jetzt verstehe ich erst, was du wirklich meinst: ..die siebtgrößte oder viertkleinste Zahl.. :D
    Mal schauen, kann ich ja noch erweitern.

  • So was meine ich:

    Spoiler anzeigen
    [autoit]


    #include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $numbers = "40,3,-2.5,-10,1000,-20202.188, +50,-1.937462,3.14"
    ConsoleWrite("Fünftkleinste Zahl: " & nNumber($numbers, 5, 0) & @CRLF) ; fünftkleinste Zahl
    ConsoleWrite("Drittgrößte Zahl: " & nNumber($numbers, 3, 1) & @CRLF) ; drittgrößte Zahl

    [/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# =====================================================================================================================
    ; Name...........: nNumber
    ; Description ...: Returns the n biggest or smallest number
    ; Syntax.........: nNumber($numbers, $n, $dir = 0)
    ; Parameters ....: $numbers - the numbers either from a string or from an array
    ; $n - search for n biggest or smallest number where n is an integer
    ; $dir - 0 search for smallest number, 1 for biggest number
    ; Return values .: Success - Returns the appropriate number and set @error to 0
    ; Failure - Returns error code:
    ; 1 - Wrong delimiter in string! Valid is comma (,) only!
    ; 2 - No numbers found!
    ; 3 - n is not an integer
    ; 4 - n is not in boundary of amount of numbers
    ; Remarks .......: Needs the function CompSort() for sorting the internal array
    ; Author ........: UEZ
    ; Version .......: 0.90 Build 2010-11-11 Beta
    ; ================================================================================================================================
    Func nNumber($numbers, $n, $dir = 0)
    If IsArray($numbers) Then
    $num = _ArrayToString($numbers, ",")
    If @error Then Return SetError(1, 0, "Error! Wrong delimiter in string! Valide is comma (,) only!")
    $numbers = $num
    EndIf
    Local $aNum = StringRegExp($numbers, "(-\d+\.\d+|\d+\.\d+|\d+)", 3)
    If Not IsArray($aNum) Then Return SetError(2, 0, "Error! No numbers found!")
    If Not IsInt($n) Then Return SetError(3, 0, "Error! n is not an integer")
    If $n < 1 Or $n > UBound($aNum) - 1 Then Return SetError(4, 0, "Error! n is not in boundary of amount of numbers")
    CompSort($aNum)
    If Not $dir Then Return SetError(0, 0, $aNum[$n - 1]) ;n smallest number
    Return SetError(0, 0, $aNum[UBound($aNum) - $n]) ;n biggest number
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;Die Komplexität liegt je nach Ausgangssituation zwischen O(n^2) (Worst-Case) und O(n*log(n)) (Best-Case).
    ;Im Best-Case ist die Liste der zu sortierenden Elemente geordnet, sobald die Schrittlänge 1 beträgt.
    ;Im Worst-Case müssen alle benachbarten Elemente nochmals getauscht werden (mehrere Durchgänge mit Schrittlänge 1).
    ;In diesem Fall ist Combsort nicht schneller als Bubblesort.
    ;Speicherverbrauch: O(c)
    ;Shrink-Faktor: 1/(1-1/e^phi) = 1.247330950103979, phi = 1.61803398874994
    Func CompSort(ByRef $aArray)
    Local $gap = UBound($aArray)
    Local $swaps, $i, $tmp
    Do
    $gap = Int($gap / 1.247330950103979)
    If $gap < 1 Then $gap = 1
    $i = 0
    $swaps = 0
    Do
    If Number($aArray[$i]) > Number($aArray[$i + $gap]) Then
    $tmp= Number($aArray[$i])
    $aArray[$i] = Number($aArray[$i + $gap])
    $aArray[$i + $gap] = $tmp
    $swaps = 1
    EndIf
    $i += 1
    Until $i + $gap > UBound($aArray) - 1
    Until $gap = 1 And $swaps = 0
    EndFunc

    [/autoit]

    Der Sortieralg. ist nicht der Schnellste. ;)

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    7 Mal editiert, zuletzt von UEZ (15. November 2010 um 15:39)