View Single Post
  #3   Report Post  
Posted to microsoft.public.excel.programming
RB Smissaert RB Smissaert is offline
external usenet poster
 
Posts: 2,452
Default Quickest way to find a row number a value

2 things to bear in mind he

1. Is the data in column 1 sorted or not?
If it is then you can do an early exit from the loop once the value in
column 1 is greater than the lookup value.
Obviously this saves a lot of time.
2. Looping through an array is a lot faster than looping through a range.
This gets even more important if you
have to do the lookup multiple times as the array has to be made only once.

The following testing code demonstrates both.
Copy the whole lot and paste to a module, then run test.

Option Explicit
Private arr As Variant
Private bFilledRange As Boolean
Private bMadeArray As Boolean
Private lStartTime As Long
Private Declare Function timeGetTime Lib "winmm.dll" () As Long

Sub test()

Dim i As Long
Dim vResult
Dim rng1 As Range
Dim rng2 As Range
Dim bSortedLookup As Boolean
Dim bUseArray As Boolean

If bFilledRange = False Then
If MsgBox("Have the lookup column sorted?", vbYesNo, _
"looking up value") = vbYes Then
bSortedLookup = True
End If
FillRange bSortedLookup
bFilledRange = True
End If

Set rng1 = Range(Cells(1), Cells(65536, 1))
Set rng2 = Range(Cells(1), Cells(65536, 2))

If MsgBox("Use the array function?", vbYesNo, _
"looking up value") = vbYes Then
bUseArray = True
End If

StartSW

If bUseArray Then
vResult = GetFirstNotZero2(rng2, "AC00BD", bSortedLookup)
Else
vResult = GetFirstNotZero(rng1, "AC00BD", bSortedLookup)
End If

StopSW , "using array = " & bUseArray

MsgBox "result = " & vResult, , "using array = " & bUseArray

End Sub

Sub FillRange(bSort As Boolean)

Dim i As Long
Dim arr1
Dim arr2

arr1 = Array("A", "B", "C", "D", 0, 1, 2, 3)
arr2 = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

For i = 1 To 65536
Cells(i, 1) = "A" & _
arr1(CLng(7 * Rnd)) & _
arr1(CLng(7 * Rnd)) & _
arr1(CLng(7 * Rnd)) & _
arr1(CLng(7 * Rnd)) & _
arr1(CLng(7 * Rnd))
Cells(i, 2) = arr2(CLng(9 * Rnd))
Next i

If bSort Then
Range(Cells(1), Cells(65536, 1)).Sort Key1:=Cells(1), _
Order1:=xlAscending, _
Header:=xlNo
End If

End Sub

Function GetFirstNotZero(rng As Range, _
vValue As Variant, _
bSortedLookup As Boolean, _
Optional lNotFoundReturn As Long = -1) As Variant

Dim c As Range

If bSortedLookup Then
For Each c In rng
If c.Value = vValue Then
If c.Offset(0, 1).Value < 0 Then
GetFirstNotZero = c.Offset(0, 1).Value
Exit Function
End If
Else
If c.Value vValue Then
Exit For
End If
End If
Next c
Else
For Each c In rng
If c.Value = vValue Then
If c.Offset(0, 1).Value < 0 Then
GetFirstNotZero = c.Offset(0, 1).Value
Exit Function
End If
End If
Next c
End If

GetFirstNotZero = lNotFoundReturn

End Function

Function GetFirstNotZero2(rng As Range, _
vValue As Variant, _
bSortedLookup As Boolean, _
Optional lNotFoundReturn As Long = -1) As Variant

Dim i As Long

If bMadeArray = False Then
arr = rng
bMadeArray = True
End If

If bSortedLookup Then
For i = 1 To UBound(arr)
If arr(i, 1) = vValue Then
If arr(i, 2) < 0 Then
GetFirstNotZero2 = arr(i, 2)
Exit Function
End If
Else
If arr(i, 1) vValue Then
Exit For
End If
End If
Next i
Else
For i = 1 To UBound(arr)
If arr(i, 1) = vValue Then
If arr(i, 2) < 0 Then
GetFirstNotZero2 = arr(i, 2)
Exit Function
End If
End If
Next i
End If

GetFirstNotZero2 = lNotFoundReturn

End Function

Sub StartSW()
lStartTime = timeGetTime()
End Sub

Function StopSW(Optional bMsgBox As Boolean = True, _
Optional vMessage As Variant, _
Optional lMinimumTimeToShow As Long = -1) As Variant

Dim lTime As Long

lTime = timeGetTime() - lStartTime

If lTime lMinimumTimeToShow Then
If IsMissing(vMessage) Then
StopSW = lTime
Else
StopSW = lTime & " - " & vMessage
End If
End If

If bMsgBox Then
If lTime lMinimumTimeToShow Then
MsgBox "Done in " & lTime & " msecs", , vMessage
End If
End If

End Function



RBS



"DG" wrote in message
...
I have a spreadsheet as follows:

column A column B
DEK S01 0
DEK S01 300
DEK S01 400
DEK S01 450
LIC G13 25
LIC G13 50
LIC G14 100
etc...

I am trying to write a function to return the first non-zero value in
column B of the Item in column A. So when I call the function
Get_Cost("DEK S01") it will return 300. When I call Get_Cost("LIC G13")
it will return 25.

A quick way of getting the row number for LIC G13 would be a help, so I
don't have to loop so much.

DG