web-dev-qa-db-fra.com

"Et" et "Ou" problèmes dans une instruction IF

J'essaie d'utiliser "Et" ou "Ou" dans une déclaration If. J'ai probablement ma syntaxe erronée.

le résultat revient faux lorsque les données doivent le rendre vrai. Voici le code:

ElseIf (origNum = "006260006" Or origNum = "30062600006") And creditOrDebit = "D" Then

'do things here

End If

-Quand je débogue et que je viens à cette ligne, elle saute dessus et n'entre pas.

-origNum est égal à "006260006" et creditOrDebit = "D".

-so je suppose que ma déclaration "Ou" ne fonctionne pas.

-Espérons que c'est une question facile et rapide. Merci!

17
Mike Kellogg

Le problème est probablement ailleurs. Essayez ce code par exemple:

Sub test()

  origNum = "006260006"
  creditOrDebit = "D"

  If (origNum = "006260006" Or origNum = "30062600006") And creditOrDebit = "D" Then
    MsgBox "OK"
  End If

End Sub

Et vous verrez que votre Or fonctionne comme prévu. Êtes-vous sûr que votre instruction ElseIf est exécutée (elle ne sera pas exécutée si l'un des if/elseif avant est vrai)?

21
assylias

Ce n'est pas une réponse, mais c'est trop long pour un commentaire.

En réponse à réponses/commentaires de JP , j'ai effectué le test suivant pour comparer les performances des 2 méthodes. L'objet Profiler est une classe personnalisée - mais en résumé, il utilise une fonction kernel32 assez précise (Private Declare Sub GetLocalTime Lib "kernel32" (lpSystemTime As SYSTEMTIME)).

Sub test()

  Dim origNum As String
  Dim creditOrDebit As String
  Dim b As Boolean
  Dim p As Profiler
  Dim i As Long

  Set p = New_Profiler

  origNum = "30062600006"
  creditOrDebit = "D"

  p.startTimer ("nested_ifs")

  For i = 1 To 1000000

    If creditOrDebit = "D" Then
      If origNum = "006260006" Then
        b = True
      ElseIf origNum = "30062600006" Then
        b = True
      End If
    End If

  Next i

  p.stopTimer ("nested_ifs")
  p.startTimer ("or_and")

  For i = 1 To 1000000

    If (origNum = "006260006" Or origNum = "30062600006") And creditOrDebit = "D" Then
      b = True
    End If

  Next i

  p.stopTimer ("or_and")

  p.printReport

End Sub

Les résultats de 5 analyses (en ms pour des boucles de 1 m):

20 juin 2012 19:28:25
nested_ifs (x1): 156 - Dernier cycle: 156 - Cycle moyen: 156
or_and (x1): 125 - Dernier cycle: 125 - Cycle moyen: 125

20 juin 2012 19:28:26
nested_ifs (x1): 156 - Dernier cycle: 156 - Cycle moyen: 156
or_and (x1): 125 - Dernier cycle: 125 - Cycle moyen: 125

20 juin 2012 19:28:27
nested_ifs (x1): 140 - Dernier cycle: 140 - Cycle moyen: 140
or_and (x1): 125 - Dernier cycle: 125 - Cycle moyen: 125

20 juin 2012 19:28:28
nested_ifs (x1): 140 - Dernier cycle: 140 - Cycle moyen: 140
or_and (x1): 141 - Dernier cycle: 141 - Cycle moyen: 141

20 juin 2012 19:28:29
nested_ifs (x1): 156 - Dernier cycle: 156 - Cycle moyen: 156
or_and (x1): 125 - Dernier cycle: 125 - Cycle moyen: 125

Remarque

Si creditOrDebit n'est pas "D", Le code de JP est plus rapide (environ 60 ms contre 125 ms pour le code ou/et).

2
assylias

J'aime assylias 'répondre, mais je voudrais le reformuler comme suit:

Sub test()

Dim origNum As String
Dim creditOrDebit As String

origNum = "30062600006"
creditOrDebit = "D"

If creditOrDebit = "D" Then
  If origNum = "006260006" Then
    MsgBox "OK"
  ElseIf origNum = "30062600006" Then
    MsgBox "OK"
  End If
End If

End Sub

Cela pourrait vous faire économiser quelques cycles de traitement, car si creditOrDebit est <> "D" il est inutile de vérifier la valeur de origNum.

Mise à jour:

J'ai utilisé la procédure suivante pour tester ma théorie selon laquelle ma procédure est plus rapide:

Public Declare Function timeGetTime Lib "winmm.dll" () As Long

Sub DoTests2()

  Dim startTime1 As Long
  Dim endTime1 As Long
  Dim startTime2 As Long
  Dim endTime2 As Long
  Dim i As Long
  Dim msg As String

  Const numberOfLoops As Long = 10000
  Const origNum As String = "006260006"
  Const creditOrDebit As String = "D"

  startTime1 = timeGetTime
  For i = 1 To numberOfLoops
    If creditOrDebit = "D" Then
      If origNum = "006260006" Then
        ' do something here
        Debug.Print "OK"
      ElseIf origNum = "30062600006" Then
        ' do something here
        Debug.Print "OK"
      End If
    End If
  Next i
  endTime1 = timeGetTime

  startTime2 = timeGetTime
  For i = 1 To numberOfLoops
    If (origNum = "006260006" Or origNum = "30062600006") And _
      creditOrDebit = "D" Then
      ' do something here
      Debug.Print "OK"
    End If
  Next i
  endTime2 = timeGetTime

  msg = "number of iterations: " & numberOfLoops & vbNewLine
  msg = msg & "JP proc: " & Format$((endTime1 - startTime1), "#,###") & _
       " ms" & vbNewLine
  msg = msg & "assylias proc: " & Format$((endTime2 - startTime2), "#,###") & _
       " ms"

  MsgBox msg

End Sub

Je dois avoir un ordinateur lent parce que 1 000 000 itérations n’ont pris que 200 ms, comme avec le test assylias '. Je devais limiter les itérations à 10 000 - hé, j'ai autre chose à faire :)

Après avoir exécuté la procédure ci-dessus 10 fois, ma procédure est plus rapide seulement 20% du temps. Cependant, lorsqu'il est plus lent, il ne l'est que superficiellement. Comme assylias a souligné, cependant, quand creditOrDebit est <>"D", ma procédure est au moins deux fois plus rapide. J'ai été en mesure de le tester raisonnablement à 100 millions d'itérations.

Et cela est la raison pour laquelle je l'ai refactoré - pour court-circuiter la logique de sorte que origNum ne nécessite pas d'évaluation lorsque creditOrDebit <> "D".

À ce stade, le reste dépend de la feuille de calcul du PO. Si creditOrDebit est susceptible d'être égal à D, utilisez la procédure assylias ', car elle fonctionnera généralement plus rapidement. Mais si creditOrDebit a un large éventail de valeurs possibles et que D n’est plus susceptible d’être la valeur cible, ma procédure l’utilisera pour éviter d’évaluer inutilement l’autre variable.

1
JimmyPena