2015-02-12 6 views
6

Я хочу найти индекс n-го наибольшего значения в массиве. Я могу сделать следующее, но он столкнулся с проблемой, когда 2 значения равны.VBA - Получить индекс n-го наибольшего значения в массиве

fltArr(0)=31 
fltArr(1)=15 
fltArr(2)=31 
fltArr(3)=52 

For i = 0 To UBound(fltArr) 
    If fltArr(i) = Application.WorksheetFunction.Large(fltArr, n) Then 
     result = i 
    End If 
Next 

п = 1 ---> 3
п = 2 ---> 2 (но я хочу, чтобы это было 0)
п = 3 ---> 2
п = 4 ---> 1

+0

Один из вариантов заключается в том, чтобы записать массив в рабочий лист с его значением индекса в ячейке рядом с ним, а затем использовать функцию рабочего листа для сортировки диапазона. Затем вы можете получить индекс для отсортированного списка. – tospig

+0

Спасибо за предложение, но я стараюсь избегать этого, если смогу. Должен быть способ сделать это программно каким-то образом! – doovers

+0

oh crap tospig, что вы ставите меня на это lol Кроме этого, возможно, посмотрите на добавление и удаление из коллекции? – Simon

ответ

6

использует второй массив, чтобы быстро получить то, что вы хотите без пробегаю по каждому элементу для каждого значения n

Sub test() 

Dim fltArr(0 To 3) 
Dim X 
Dim n As Long 
Dim lngPos As Long 

fltArr(0) = 31 
fltArr(1) = 15 
fltArr(2) = 31 
fltArr(3) = 52 

X = fltArr 

For n = 1 To 4 
    lngPos = Application.WorksheetFunction.Match(Application.Large(X, n), X, 0) - 1 
    Debug.Print lngPos 
    X(lngPos) = Application.Max(X) 
Next 

End Sub 
+2

Может кто-нибудь объяснить, как это работает? Что такое 'X (lngPos) = Application.Max (X)'? –

+0

Как это работает: X - это вспомогательный массив, в котором наибольший элемент, найденный в нем, впоследствии перезаписывается максимальным значением 52. Таким образом, в каждом цикле осталось меньше элементов для проверки через 'Match' для значения nth-' Large'. –

2

Edit:

Public Sub RunLarge() 
Dim n%, i%, result%, count% 
Dim fltArr(3) As Integer 
Dim iLarge As Integer 

fltArr(0) = 31: 
fltArr(1) = 15: 
fltArr(2) = 31: 
fltArr(3) = 52 
n = 1 

Debug.Print " n", "iLarge", "result" 

While n <= 4 
    count% = n - 1 
    iLarge = Application.WorksheetFunction.Large(fltArr, n) 

    For i = 0 To UBound(fltArr) 
     If fltArr(i) = iLarge Then 
      result = i 
      count% = count% - 1 
      If count% <= 0 Then Exit For 
     End If 
    Next 

    Debug.Print n, iLarge, result 
    n = n + 1 
Wend 
End Sub 

результат:

n   iLarge  result 
1    52   3 
2    31   0 
3    31   2 
4    15   1 
+1

OP хочет 3,0,2,1 – tospig

+1

Извинения, я написал сообщение слишком быстро, и я совершил ошибку там.Результаты, полученные вами, были такими же, как мои! Я сейчас отредактирую вопрос! – doovers

+0

Ваше правление дает 3,0,0,1, что все еще некорректно – tospig

0

Это немного «грязный», но видя, как вы в Excel ...

' Create a sheet with codename wsTemp... 

For i = 0 To UBound(fltArr) 
    wsTemp.cells(i,1) = i 
    wsTemp.cells(i,2) = fltArr(i) 
Next 

with wsTemp 
    .range(.cells(1,1),.cells(i,2)).sort(wsTemp.cells(1,2),xlDescending) 
end with 

Result = wsTemp.cells(n,1) 

Тогда вы могли бы также расширить сортировку «сортировку по значению, то по индексу», если вы хотите контроль «который из двух равных 2nds я должен выбрать» вещь ...

0

Возможно, это:

Public Sub RunLarge() 
Dim fltArr() As Variant, X As Long 
fltArr = Array(31, 15, 31, 52) 'Create the array 
For X = 1 To 4 'Loop the number of large values you want to index 
    For i = LBound(fltArr) To UBound(fltArr) 'Loop the array 
     If fltArr(i) = Application.WorksheetFunction.Large(fltArr, 1) Then 'Find first instance of largest value 
      result = i 
      fltArr(i) = -9999 'Change the value in the array to -9999 
      Exit For 
     End If 
    Next 
    Debug.Print result 
Next 
End Sub 

Как считает первый экземпляр большого числа он заменяет его -9999 так далее следующая развертка будет выбирать следующий экземпляр.

+0

Хорошая идея, но, к сожалению, набор данных не может быть изменен – doovers

+0

Мне нравится идея, однако я думаю, что это может иметь проблему: при запуске с n = 2 (или X = 2 в этом случае) наибольшее число будет 52 , а не 31. –

+0

Если набор данных можно изменить, вы всегда можете скопировать его во второй массив и работать над этим, любые изменения не будут иметь никакого значения, так как ваш исходный массив все равно останется неповрежденным. El Scipto. Хорошая точка :) –

0

Вот код для нахождения п-й по величине элемента в коллекции. Все, что вам нужно сделать, это написать функцию, которая вернет индекс.

Sub testColl() 
    Dim tempColl As Collection 
    Set tempColl = New Collection 
    tempColl.Add 57 
    tempColl.Add 10 
    tempColl.Add 15 
    tempColl.Add 100 
    tempColl.Add 8 


    Debug.Print largestNumber(tempColl, 2) 'prints 57 
End Sub 

и самой функции, которую я мог бы придумать.

Function largestNumber(inputColl As Collection, indexMax As Long) 
     Dim element As Variant 
     Dim result As Double 
     result = 0 

     Dim i As Long 
     Dim previousMax As Double 

     For i = 1 To indexMax 
      For Each element In inputColl 
       If i > 1 And element > result And element < previousMax Then 
        result = element 
       ElseIf i = 1 And element > result Then 
        result = element 
       End If 
      Next 

      previousMax = result 
      result = 0 
     Next 

     largestNumber = previousMax 
End Function 
Смежные вопросы