6

I want to find the index of the nth largest value in an array. I can do the following but it runs into trouble when 2 values are equal.

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

n=1 ---> 3
n=2 ---> 2 (but I want this to be 0)
n=3 ---> 2
n=4 ---> 1

10
  • One option would be to write the array to a worksheet with it's index value in the cell next to it, then use the worksheet function to sort the range. You can then pick up the index for the sorted list. Commented Feb 12, 2015 at 3:49
  • Thanks for the suggestion but I'm trying to avoid that if I can. There must be a way of doing it programmatically somehow! Commented Feb 12, 2015 at 4:09
  • oh crap tospig you bet me to it lol Apart from that, perhaps look at adding and removing from a collection? Commented Feb 12, 2015 at 4:14
  • 1
    hello doovers, I updated the code. It might be, that all you need is to add an "Exit for" to the loop. Please see in the code. Commented Feb 12, 2015 at 4:39
  • 1
    Hello, I reedited my answer. See if it helps. I added a new variable named "count" to help solve the issue. Commented Feb 12, 2015 at 5:10

5 Answers 5

6

Uses a second array to quickly get what you want without looping through each element for every value of 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
Sign up to request clarification or add additional context in comments.

2 Comments

Can someone please explain how it works? What is that for X(lngPos) = Application.Max(X)?
How it works: X is a helper array where the greatest element found latest therein is afterwards overwritten by the maximum value of 52. So in each loop there are fewer elements to check via Match for a nth- Large value.
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

result:

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

3 Comments

Apologies, I wrote the post too quick and I made a mistake there. The results you got were same as mine! I'll edit question now!
Nice one mate, I reckon you've cracked it! Gonna go run some tests and I'll be back to mark it as the answer!
Although your answer work perfectly, I marked brettdj's post as the answer because in my case where the array is very large, his solution performs a lot better since there is only one loop. Thanks for the help though!
0

It's a bit "dirty" but seeing as you're in 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)

Then you could also expand the sort to "sort by value then by index" if you wanted to control the "which of two equal 2nds should i choose" thing...

Comments

0

Perhaps this:

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

As it finds the first instance of the large number it replaces it with -9999 so on the next sweep it will pick the next instance of it.

3 Comments

Good idea but unfortunately the dataset can't be modified
I love the idea, however I think it might have a problem: when starting from n = 2 (or X = 2 in this case), then the largest number will be 52, not 31.
If the dataset can be modified, you could always copy it to a second array and work on that, any modifications make no difference as your original array would still be intact. El Scipto. Good point :)
0

Here's code for finding the nth largest item in collection. All you need to do is to write a function that would return it's index.

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

and the function itself, the easiest I could come up with.

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.