问题
I have 2 questions, the first one is about an excel formula that i can't replicate in VBA even though i've used the record macro to retrieve the formula, the second comes because i couldnt solve my first question and is about code efficiency: Basically in the cell AR2 i'm putting an excel formula :
IF=(P2="LDN";"UK;IF(P2="MAD";"SPAIN"
IF(P2="PRA";"CZECH REPUBLIC";"")))))))))
i m doing this for a bunch of countries.
and then i m doing the autfill cell destination on my second row till the last row with data on my sheet to get the result. The main issue is that in excel it works well however when coding in VBA with vba recorder i have an error in the below code. although i just copy pasted the result of the vba recorder. Please find the code below.
i = Range("A:A").Find("*", [A1], xlValues, xlWhole, xlByRows, xlPrevious).Row
Range("AR2").Select
ActiveCell.FormulaR1C1 = _
"=IF(RC[-28]=""LDN"",""UK"",IF(RC[-28]=""MAD"",""SPAIN"",IF(RC[-28]=""STO"",""SWEDEN"",IF(RC[-28]=""DUB"",""IRELAND"",IF(RC[-28]=""SAO"",""BRASIL"",IF(RC[-28]=""PAR"",""FRANCE"",IF(RC[-28]=""TOR"",""CANADA"",IF(RC[-28]=""TOK"",""JAPAN"",IF(RC[-28]=""ZUR"",""SWITZERLAND"",IF(RC[-28]=""HKG"",""HONG KONG"",IF(RC[-28]=""HEL"",""FINLAND"",IF(RC[-28]=""MIL"",""ITALY"",IF(R"& _
""FRA"",""GERMANY"",IF(RC[-28]=""COP"",""DANEMARK"",IF(RC[-28]=""BRU"",""BELGIUM"",IF(RC[-28]=""AMS"",""NETHERLANDS"",IF(RC[-28]=""SIN"",""SINGAPORE"",IF(RC[-28]=""SEO"",""SOUTH KOREA"",IF(RC[-28]=""OSL"",""NORWAY"",IF(RC[-28]=""LIS"",""PORTUGAL"",IF(RC[-28]=""NYK"",""USA"",IF(RC[-28]=""VIE"",""AUSTRIA"",IF(RC[-28]=""LUX"",""LUXEMBOURG"",IF(RC[-28]=""JOH"",""SOUTH AF"& _
"(RC[-28]=""MEX"",""MEXICO"",IF(RC[-28]=""SYD"",""AUSTRALIA"",IF(RC[-28]=""TAI"",""TAIWAN"",IF(RC[-28]=""VAR"",""POLAND"",IF(RC[-28]=""BUD"",""HUNGARY"",IF(RC[-28]=""IST"",""TURKEY"",IF(RC[-28]=""BAN"",""INDIA"",IF(RC[-28]=""MOS"",""RUSSIA"",IF(RC[-28]=""TEL"",""ISRAEL"",IF(RC[-28]=""KUA"",""MALAYSIA"",IF(RC[-28]=""ATH"",""GREECE"",IF(RC[-28] =""PRA"",""CZECH REPUBLIC"& _
"))))))))))))))))))))))))))))))))))"
Range("AR2").Select
Selection.AutoFill Destination:=Range("AR2:AR" & i)
As the above code didnt worked i tried to do it in vba using Loop however i found out that it takes ages to get the result as i have almost 20k rows.... 5min to process insteand of instant result with excel formula : The code of my loop is here :
For j = 2 To i
If Range("P" & j) = "AMS" Then Range("AR" & j) = "NETHERLANDS"
If Range("P" & j) = "ATH" Then Range("AR" & j) = "GREECE"
If Range("P" & j) = "BAN" Then Range("AR" & j) = "INDIA"
If Range("P" & j) = "BRU" Then Range("AR" & j) = "BELGIUM"
If Range("P" & j) = "BUD" Then Range("AR" & j) = "HUNGARY"
If Range("P" & j) = "COP" Then Range("AR" & j) = "DANEMARK"
.
.
.
.
.
If Range("P" & j) = "VAR" Then Range("AR" & j) = "POLAND"
If Range("P" & j) = "VIE" Then Range("AR" & j) = "AUSTRIA"
If Range("P" & j) = "ZUR" Then Range("AR" & j) = "SWITZERLAND"
Next j
If the excel formulat doesnt work in VBA, how can i code in an efficient and fast way in order to get the countries for at least 20k rows without having to wait and get the result almost instantanely like for the excel formula auto fill mode.
Many thanks fo ryour help Olivier
回答1:
Okay, a few very simple suggestions:
Dim vals() As Variant
vals = Range("P1:P1000") ' Substitute with the range you're looking at
Dim i As Integer
Dim val As String
For i = LBound(vals, 1) To UBound(vals, 1)
val = CStr(vals(i, 1))
Select Case val
Case "AMS"
Range("AR" & i + some_fixed_offset_if_needed) = "NETHERLANDS"
Case "AR":
' .....
' Case .....
End Select
Next i
First of all, if you access a range's value very often, don't access the range object each time. This is very slow. Save its value to a temporary variable, and access that variable instead. And better yet - save the entire range you're looking through in an array variable, and then loop through that array.
Second, if the cases are mutually exclusive, don't just write a ton of If Statements - Use If ... ElseIf ...
etc. That way, it doesn't need to check every other condition if it's already found the matching one. In the code above, I've just used a select case statement for that purpose.
Check if that speeds it up a little. It not, you could try adding the possible short codes to a Scripting.Dictionary as keys, and the replacements (e.g. "NETHERLANDS") as values. Dictionary lookups are very very fast.
And if that's still slower, you can always use WorksheetFormula.something to access sheet functions in VBA.
回答2:
You can easily do this without VBA as shown below; but i'll also give a VBA solution further down.
First, though, I'll say that hard-coding your lookup data (i.e. writing city codes and country names directly in your VBA program) is bad practice. It makes it hard for a human to read and check them now, and inconvenient to change them later.
In this example I put all the city codes and country names in a look-up table to the right in the Excel sheet (but you could put it in some other hidden sheet if your prefer). To then match the city codes listed in column A to the appropriate country, I just lookup the city code in the table using e.g. in cell B2:
=INDEX($F$4:$F$12,MATCH(A2,$E$4:$E$12,0))
Copy the formula all the way down.

If you really want VBA, you can get the exact same result (given the same input and look-up table in the same location) with this short piece of code:
Dim i As Long
Dim cityCodes
Dim countryNames
Dim listOfCountryNames
Dim listOfCityCodes
'Read look-up table from sheet.
listOfCityCodes = WorksheetFunction.Transpose(Range("E4:E12").Value)
listOfCountryNames = WorksheetFunction.Transpose(Range("F4:F12").Value)
'Read the input city codes from sheet to array
cityCodes = Range("A2:A9").Value
'Make a blank array of same size to receive the corresponding country names
ReDim countryNames(LBound(cityCodes, 1) To UBound(cityCodes, 1), _
LBound(cityCodes, 2) To UBound(cityCodes, 2))
'Lookup individual country names one by one, write them in array
For i = LBound(cityCodes, 1) To UBound(cityCodes, 1)
countryNames(i, 1) = listOfCountryNames( _
WorksheetFunction.Match(cityCodes(i, 1), listOfCityCodes, 0))
Next i
'Write country names from array to sheet
Range("B2:B9").Value = countryNames
You'll notice that I read everything at once from the sheet to arrays, then do all manipulations in those arrays, then finally write back to the sheet. This executes significantly faster than doing your read/write in individual cells one by one.
来源:https://stackoverflow.com/questions/25546497/alternative-to-using-loop-to-make-code-run-faster