2 minimale Zahlen rausfiltern

  • Excel

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von franz.steinmeyer.

    2 minimale Zahlen rausfiltern

    Ich habe das folgende Programm geschrieben, dabei wollte ich die 2 minimalsten Werte herausfischen:

    Sub DP()

    Dim l As Integer
    Dim Sum(1 To 24) As Integer
    Dim i As Integer
    Const N = 4
    Dim f(N) As Integer


    l = Range("b6").Value

    f(1) = Range("b2").Value
    f(2) = Range("b3").Value
    f(3) = Range("b4").Value
    f(4) = Range("b5").Value

    For i = 1 To N
    Min = f(1)
    If f(i) < Min And f(i) >= 0 Then
    Min = f(i)
    End If
    Next i

    For i = 1 To N
    Min2 = f(1)
    If f(i) < Min2 And f(i) > =0 And f(i) >= Min Then
    Min2 = f(i)
    End If

    Next i

    End Sub

    Das Problem liegt darin, dass nur der erste minimale Wert angezeigt wird und bei der zweiten Schleife erkennt es nicht, dass die Werte auch größer als der minimalste Wert sein soll. Könnt ihr mir bitte helfen? Wie kann ich das umändern?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „franz.steinmeyer“ ()

    ahoi,

    hast du denn schonmal ordentlich getestet ?
    mit 1,2,3,4 kann nur die 1 reinkommen
    bei 4,3,2,1 geht es glaub ich wenn ich mich nicht vertan habe.


    wenn ich dir einen tipp geben darf
    ich würde dir den bubble-sort algorithmus empfehlen dadurch hast du die beiden kleinsten werte
    immer in den ersten beiden indezes

    EDIT: hab deinen fehler gefunden

    Visual Basic-Quellcode

    1. For i = 1 To N
    2. Min2 = f(1)
    3. If f(i) < Min2 And f(i) > 0 And f(i) > Min Then
    4. Min2 = f(i)
    5. End If


    du setzt in jedem schleifen durchlauf min und min2 immer wieder auf den ersten index des arrays
    das muss vor der schleife passieren nicht in der schleife
    also

    Visual Basic-Quellcode

    1. Min2 = f(1)
    2. For i = 1 To N
    3. If f(i) < Min2 And f(i) > 0 And f(i) > Min Then
    4. Min2 = f(i)
    5. End If
    6. Next
    Grüße Manu

    Was Gott dem Menschen erspart hat, kann der Computer.
    Billy ©, (*1932), Schweizer Aphoristiker
    Quelle: www.Aphorismen.de

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Manü“ ()

    Warum sortieren, wenn nur die zwei kleinsten benötigt werden?

    zb

    Visual Basic-Quellcode

    1. Public Sub SmallestOfThree(ByRef Num1 As Integer, ByRef Num2 As Integer, ByVal TestNum As Integer)
    2. If TestNum >= Max(Num1, Num2) Then Exit Sub
    3. Dim tmp As Integer
    4. tmp = Min(Num1, Num2)
    5. Num1 = TestNum
    6. Num2 = tmp
    7. End Sub


    Num1 und Num2 mit dem Maximalwert für Integer (oder Long, oder Byte, je nachdem was man braucht) vorbelegen und dann einfach jede einzelne Zahl testen.
    @PIC: is auch ne lösung aber ich dachte mir da er ja scheinbar anfänger ist kann mans ruhig erstmal langsam angehen ;)
    Grüße Manu

    Was Gott dem Menschen erspart hat, kann der Computer.
    Billy ©, (*1932), Schweizer Aphoristiker
    Quelle: www.Aphorismen.de

    Manü schrieb:

    ruhig erstmal langsam angehen

    Na dann würde ich aber auch nicht gleich mit nem BubbleSort anfangen ;)

    Anyway: Wenn man das Problem "Die zwei kleinsten Zahlen aus n möglichen" betrachtet, stellt man fest, dass der Vergleich "a zu b zu c" irgendwie sehr schön in eine eigene Funktion ausgelagert werden kann. Hat dann auch den Vorteil, dass sich das ganze etwas angenehmer und leichter liest, Denn selbst ohne jegliche Kommentare ist der Funktionsname ja schon irgendwie sehr hilfreich ;)
    (ggfs ändern auf "SmallestTwoOfThree" dann wird's ja richtig eindeutig)
    ich denke man könnte einiges abkürzen
    aber ich denke bubble ist noch erstmal einfach zu verstehen
    außerdem will er ja sicher was lernen und die ersten autos sind auch
    nicht gleich von 0 auf 100 in 4 sekunden ;)
    Grüße Manu

    Was Gott dem Menschen erspart hat, kann der Computer.
    Billy ©, (*1932), Schweizer Aphoristiker
    Quelle: www.Aphorismen.de
    picoflop, ich habe ihr Code nicht so richtig verstanden. Ich bin echt ein Anfänger und komme mit solchen komplizierten Ausdrücken nicht klar, könntest du mir bitte mehr dazu schreiben und den ganzen Quellcode hier posten? Warum sollen die Num, Num1 Parameter in die Klammer gesetzt werden und dort deklariert werden? Danke!

    Manü, danke dir auch für die Hilfe, aber trotzdem wird immer der erste Wert für min und min2 ausgegeben. :( :?:
    Ich habe ja in den Zellen auch die negativen Zahlen. Wenn ich am Anfang der Schleife als Min eine negative Zahl einsetze, kommt sie als minimaler Wert raus, obwohl ich angegeben habe nur die positiven Werte anzuzeigen ?(

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „franz.steinmeyer“ ()

    franz.steinmeyer schrieb:

    Warum sollen die Num, Num1 Parameter in die Klammer gesetzt werden und dort deklariert werden?

    Du weist also nicht was eine "Funktion" (Methode, Prozedur, ...) ist? Dann solltest du das schleunigst mal lernen! Das ist eine Grundlage, die man dringend braucht.

    Der Code ist "komplett". Es handelt sich um eine Funktion, die von 3 Zahlen, die zwei kleinsten findet, bzw eigentlich um eine Funktion, die bei zwei gegebenen Zahlen (den "vermutlich" kleinsten) eine dritte Zahl prüft und falls diese kleiner ist als mindestens eine der beiden ursprünglichen Zahlen, die größere der beiden ursprünglichen Zahlen durch die neue Zahl ersetzt.
    picoflop, danke, ich werde dein Tipp beherzigen.
    Aber wo soll ich dann die Werte
    f(1) = Range("b2").Value
    f(2) = Range("b3").Value
    f(3) = Range("b4").Value
    f(4) = Range("b5").Value

    eintragen? In die Function rein oder getrennt und dann den Sub vor der Function schließen?
    Meine Funktion, so wie sie ist, ist fertig. Da braucht man nix "eintragen".
    Was man tun muss, ist die Funktion "aufzurufen". Dabei "übergibt" man dann die Werte die im Funktionskopf deklariert werden.

    also zb.
    Call SmallestOfThree(a, b, c)

    Da "a" und "b" die beiden Kandidaten sind, ruft man die Funktion (in einer Schleife) mehrfach auf, wobei man VOR der Schleife a und b auf etwas sinnvolles setzt und in der Schleife jeweils mit einem anderen/neuen c prüft.

    Nehmen wir mal an, dass die zu prüfenden Zahlen in einem Array stehen
    Dann sieht das in etwas SO aus:

    Num1 = Array(0)
    Num2 = Array(1)
    For i = 2 to MaximalerArrayIndex
    Call SmallestOfThree(Num1, Num2, Array(i))
    next i
    Call ZeigeDieBeidenNiedrigstenNummern(Num1, Num2)
    Da es Max und Min in VBA tatsächlich nicht gibt, schreibt man sich die halt selbst.

    Falls VBA "IIf" unterstützt, kann man statt Wert = Max(a,b) auch

    Wert = IIf(a > b, a, b)

    schreiben. Für Min() dann analog.

    sähe dann so aus:

    Visual Basic-Quellcode

    1. Public Sub SmallestOfThree(ByRef Num1 As Integer, ByRef Num2 As Integer, ByVal TestNum As Integer)
    2. If TestNum >= IIf(Num1 > Num2, Num1, Num2) Then Exit Sub
    3. Dim tmp As Integer
    4. tmp = IIf(Num1 < Num2, Num1, Num2)
    5. Num1 = TestNum
    6. Num2 = tmp
    7. End Sub


    Mit IIf ist es schneller als wenn man eigene Funktionen für Min() und Max() schreibt, aber dafür leidet natürlich die Lesbarkeit etwas.
    picoflop, wow, danke!!! Ich habe heute noch ein Mal versucht und es hat geklappt.
    Das Problem jetzt aber ist, dass es dort in array auch negative Zahlen vorkommen und ich das bei der Prüfung auch berücksichtigen möchte, so dass die 2 minimalen Zahlen positiv und kleiner gleich l sind.
    Wisst ihr wie das zu machen ist? Ich hab rumprobiert, ging aber nicht,komisch :(

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „franz.steinmeyer“ ()

    @ franz

    Hier die Lösung, habe Deinen Code beibehalten nur so angepasst das richtig verarbeitet wird. Wieso ich was verändert habe, habe ich Dir in den Kommentaren dazu geschrieben. Kopiere es einfach in den Editor und es wird einfach zu lesen sein. ;)

    Auf der Basis müsstest Du dann auch alleine erkennen können wo und wie die weiteren Prüfungen einzubauen sind. Aber trotzdem bleib am Thema eigene Functions dran. Das ist enorm wichtig. ;)

    Sub DP()

    Dim l As Integer
    Dim Sum(1 To 24) As Integer
    Dim i As Integer
    ' auch bei Konstanten den Typ deklarieren, sonst wird Typ Variant angenommen
    Const N As Integer = 4
    ' und wenn dann alle Variabelen deklarieren ;)
    Dim Min As Integer, Min2 As Integer
    Dim f(N) As Integer


    l = Range("b6").Value

    f(1) = Range("b2").Value
    f(2) = Range("b3").Value
    f(3) = Range("b4").Value
    f(4) = Range("b5").Value

    ' Startwert für Min muss vor der Schleife gesetzt werden
    Min = f(1)
    ' Schleife beginnt dann bei zwei, da 1 ja schon vorab eingelesen wurde, kann aber auch bei 1 beginnen
    For i = 2 To N
    If f(i) < Min And f(i) >= 0 Then
    Min = f(i)
    End If
    Next i

    ' wiederum Startwert für Min vor Schleife setzen, hier aber vergleichen mit Inhalt Min
    ' wenn array1 = inhalt Min dann array2 einlesen
    If Min <> f(1) Then
    Min2 = f(1)
    Else
    Min2 = f(2)
    End If

    ' hier fängt Schleife bei 1 an, da nicht sicher ist ob nun array1 oder array2 eingelesen wurde
    For i = 1 To N
    ' nur den Wert verarbeiten wenn es ungleich Inhalt Min ist um zu vermeiden, dass der erste niedrigste
    ' Wert nochmals als niedrigster gefunden wird
    If f(i) <> Min Then
    If f(i) < Min2 And f(i) >= 0 Then
    Min2 = f(i)
    End If
    End If

    Next i

    End Sub

    Gruß

    Rainer
    raist10, danke, aber ich habe hier noch ein Problem rausgefunden. Wenn ich am Anfang als Min = f(1) setze und f(1) negativ ist, dann kommt am Ende als minimale Zahl auch negative Zahl raus, was ich aber vermeiden möchte, denn meine 2 minimalen Zahlen sollen positiv und kleiner gleich 100 sein. ?(
    Womit wir wieder beim Thema der Gültigkeitsprüfungen wären. ^^

    Hab Dir jetzt mal die Gültigkeitsprüfung beim Einlesen der Werte aus B2 bis B5 eingebaut. Heisst die Werte dort werden nur in das Array eingelesen, wenn Sie größer gleich Null und gleichzeitig kleiner gleich 100 sind. Erfüllt ein Wert die Bedingungen nicht, kommt er nicht ins Array und wird bei der folgenden Ermittlung des niedrigsten Wertes nicht berücksichtigt.

    Option Base wird im Modul ganz zu anfang reingeschrieben, damit wird die kleinste Dimension des Arrays festgelegt. Normalerweise ist die kleinste Dimension 0, ist aber nicht wirklich angenehm für Schleifen bei denen der Zähler bei 1 anfängt. Daher durch die Anweisung Option Base 1 die kleinste Dimension eines Arrays auf den Wert 1 gesetzt. Also diese anweisung bitte auch mit in das Modul einfügen. ;)


    ' Array auf 1 als kleinsten Array-Wert setzen, wäre ansonsten 0
    Option Base 1

    Sub DP()

    Dim l As Integer
    Dim Sum(1 To 24) As Integer
    Dim i As Integer
    ' und wenn dann alle Variabelen deklarieren
    Dim Min As Integer, Min2 As Integer
    ' Array als Variant deklarieren, da wenn als Integer deklariert auch ein leeres Arrayfeld den gültigen Wert 0 enthält
    Dim f() As Variant

    ' Array f auf 1 Dimension dimmen, ohne Erhalt vorhandener Einträge
    ReDim f(1)

    ' Was beinhaltet l für diese Sub?
    l = Range("b6").Value

    For i = LBound(f) To 4
    If Range("b" & i + 1).Value >= 0 And Range("b" & i + 1).Value <= 100 Then
    f(UBound(f)) = Range("b" & i + 1).Value
    ' da nun 1 Dimension belegt ist, Array f um 1 Dimension erhöhen und dabei vorhandene Werte durch Einsatz Preserve erhalten
    ReDim Preserve f(UBound(f) + 1)
    End If
    Next i

    ' Bei Error Next hier einsetzen, da Fehler kommt wenn Array nur 1 Dimension enthält
    On Error Resume Next
    ' Höchste Dimension wieder wegnehmen da leer ist
    ReDim Preserve f(UBound(f) - 1)

    ' Prüfen ob Array mehr als 1 Eintrag hat
    If UBound(f) = 1 Then
    ' wenn nur 1 Eintrag, dann gucken ob der leer ist und wenn ja dann raus
    If f(1) = "" Then
    Exit Sub
    End If
    End If

    ' Startwert für Min muss vor der Schleife gesetzt werden
    Min = f(LBound(f))

    ' Schleife beginnt bei niedrigster Array-Dimension und zählt rauf bis höchste Array-Dimension
    For i = LBound(f) To UBound(f)
    If f(i) < Min Then
    Min = f(i)
    End If
    Next i

    ' wiederum Startwert für Min vor Schleife setzen, hier aber vergleichen mit Inhalt Min
    ' wenn array niedrigste Dimension = inhalt Min dann array niedrigste Dimension + 1 einlesen
    If Min <> f(LBound(f)) Then
    Min2 = f(LBound(f))
    Else
    ' sollte ein Array nur 1 Dimension beinhalten, dann gibt es hier Fehlermeldung, die aber durch
    ' obige Anweisung On Error Resume Next zu keinem Programmabbruch führt
    Min2 = f(LBound(f) + 1)
    End If

    ' und nur wieder Array von niedrigster dimension bis zur höchsten Dimension durchlaufen
    For i = LBound(f) To UBound(f)
    ' nur den Wert verarbeiten wenn es ungleich Inhalt Min ist um zu vermeiden, dass der erste niedrigste
    ' Wert nochmals als niedrigster gefunden wird
    If f(i) <> Min Then
    If f(i) < Min2 Then
    Min2 = f(i)
    End If
    End If
    Next i

    MsgBox "Minimalster Wert ist: " & Min

    If Min2 <> Min Then
    MsgBox "Zweiter minimalster Wert ist: " & Min2
    Else
    MsgBox "Kein zweiter minimalster Wert zu finden."
    End If

    End Sub

    Habe hier mal als kleines Beispiel für Dich die Funktionen ReDim, ReDim Preserve, LBound und UBound genutzt. Die sind wichtig, wenn man mit Array dynamisch arbeiten will.

    Gruß

    Rainer