Пять самых больших значений в столбце


Моя цель состоит в том, чтобы отправить сообщение о пяти самых больших значениях в столбце. Но поскольку я использую ">", значения в столбце перед L не учитываются для La или Lb, если на то пошло. Например:

7
8
5
3
6
2

L становится 8, но La (второй по величине) становится 6 (но должен был быть 7), Lb (третий по величине) становится 2, а Lc =0, Ld=0.

Sub maxtest3()

Dim L As Integer, La As Integer, Lb As Integer, Lc As Integer, Ld As Integer
Dim a As Variant
L = 0
La = 0
Lb = 0
Lc = 0
Ld = 0


For Each a In Range("A1:A20")
If a.Value > L Then
    L = a.Value
        Else
        If a.Value > La Then
        La = a.Value
            Else
            If a.Value > Lb Then
            Lb = a.Value
                Else
                If a.Value > Lc Then
                Lc = a.Value
                    Else
                    If a.Value > Ld Then
                    Ld = a.Value
                        Else
                    End If
                End If
            End If
        End If
    End If
Next
                MsgBox (L & " " & La & " " & Lb & " " & Lc & " " & Ld)
End Sub
Я знаю, что тот, кто видит это, может решить проблему с помощью одной строки кода, но, пожалуйста, воздержитесь от этого. это делается ради обучения новичка.
4 3

4 ответа:

Вложенные операторы If ... Else ... можно было бы проще записать в виде оператораSelect Case . Это может даже улучшить читаемость.

Проблема заключалась в том, что последующие значения перезаписывали предыдущие. Существующие значения необходимо переместить дальше в очередь, прежде чем они будут перезаписаны. Хотя следующий код немного многословен, он должен адекватно продемонстрировать решение.

Sub maxtest3()
    Dim L As Variant, a As Range, rng As Range

    Set rng = Range("A1:A" & Cells(Rows.Count, "A").End(xlUp).Row)
    ReDim L(1 To 5)

    For Each a In rng
        Select Case a.Value
            Case Is > L(1)
                L(5) = L(4)
                L(4) = L(3)
                L(3) = L(2)
                L(2) = L(1)
                L(1) = a.Value
            Case Is > L(2)
                L(5) = L(4)
                L(4) = L(3)
                L(3) = L(2)
                L(2) = a.Value
            Case Is > L(3)
                L(5) = L(4)
                L(4) = L(3)
                L(3) = a.Value
            Case Is > L(4)
                L(5) = L(4)
                L(4) = a.Value
            Case Is > L(5)
                L(5) = a.Value
        End Select
    Next a

    MsgBox Join(L, Chr(32))

End Sub

Я изменил ваш L x vars на простой одномерный массив. Это позволяет использовать функцияJoin для упрощения конкатенации строк в MsgBox.

Sub test()

Range("A1", "A6").Copy 'adjust the column you want to sort
Range("B1", "B6").PasteSpecial 'adjust to a free column

Columns("B").Sort key1:=Range("B1"), _ 'adjust
  order1:=xlDescending, Header:=xlNo

Dim i As Integer
Dim str As String

For i = 1 To 5

    str = str & " " & Cells(i, 2).Value 'adjust to the column you pasted too

Next

Range("B1", "B6").Clear 'adjust

MsgBox str

End Sub

Джипед уже объяснил логику, почему ваша попытка If Block терпит неудачу. С другой стороны, поскольку вы используете Excel, вы можете использовать доступные функции .
Что-то вроде:

Sub maxtest3()
    Dim L As Integer, La As Integer, Lb As Integer, Lc As Integer, Ld As Integer

    With Application.WorksheetFunction
        L = .Large(Range("A1:A20"), 1)
       La = .Large(Range("A1:A20"), 2)
       Lb = .Large(Range("A1:A20"), 3)
       Lc = .Large(Range("A1:A20"), 4)
       Ld = .Large(Range("A1:A20"), 5)
    End With
    MsgBox (L & " " & La & " " & Lb & " " & Lc & " " & Ld)
End Sub

Надеюсь, это поможет.

Sub maxtest3()

Dim L(4) As Integer
Dim Lp(4) As Integer
Dim i, j As Integer

Dim RC As Boolean

Dim a As Variant

For i = 0 To 4

    L(i) = 0

    For Each a In Range("A1:A20")

        'If the current cell location has been used before sets RC = False
        RC = True
        For j = 0 To i - 1
            If Lp(j) = a.Row Then RC = False
        Next j

        'If the current cell value is greater than the current value in L(i) 
        'AND the location has not been used already, sets L(i) to the current
        'value and sets Lp(i) to the location of the current value
        If a.Value > L(i) And RC = True Then
            L(i) = a.Value
            Lp(i) = a.Row
        End If
    Next
Next i

MsgBox (L(0) & " " & L(1) & " " & L(2) & " " & L(3) & " " & L(4))

Конец Sub

Эта программа повторяет цикл выбора диапазона пять отдельных раз. Каждый раз, когда он делает петлю, он выбирает следующее по величине число. Переменные L(i) и Lp(i) представляют собой массивы из пяти элементов, каждый из которых будет содержать ваши пять самых больших чисел и их позиции в выбранном диапазоне. Это позволяет программе пропускать числа, которые она уже выбрала как более крупные.

Что нужно учитывать: Если одно и то же число появляется больше, чем попав в диапазон значений, каждый экземпляр можно выбрать как "самое большое" значение.

В настоящее время эта программа рассматривает только положительные целые числа. Если бы все числа в диапазоне были отрицательными числами, он вернул бы все нули. Чтобы исправить это, измените значение инициализации для L (i) с 0 на -32768 (самое большое отрицательное значение, которое можно сохранить в целом числе)