Domanda

Posso raggiungere

if (a == "b" || "c")

anziché

if (a == "b" || a== "c")

È stato utile?

Soluzione

No, puoi fare:

if (new[] { "b", "c" }.Contains(a))

se hai le LINQ disponibili, ma questo non è certo un miglioramento.


In risposta al commento sulle prestazioni, ecco alcuni codici di temporizzazione di base. Nota che il codice deve essere visualizzato con un occhio critico, potrei aver fatto delle cose qui che hanno distorto i tempi.

I risultati prima:

||, not found: 26 ms
||, found: 8 ms
array.Contains, not found: 1407 ms
array.Contains, found: 1388 ms
array.Contains, inline array, not found: 1456 ms
array.Contains, inline array, found: 1427 ms
switch-statement, not interned, not found: 26 ms
switch-statement, not interned, found: 14 ms
switch-statement, interned, not found: 25 ms
switch-statement, interned, found: 8 ms

Tutto il codice è stato eseguito due volte e ha superato solo nr. 2 è stato riportato, per rimuovere JITting overhead dall'equazione. Entrambi i passaggi hanno eseguito ogni tipo di controllo un milione di volte e lo hanno eseguito entrambi dove l'elemento da trovare era uno degli elementi in cui trovarlo (ovvero, l'istruzione if eseguiva il suo blocco), e una volta dove l'elemento non era (il blocco non verrebbe eseguito). Vengono riportati i tempi di ciascuno. Ho testato sia un array pre-costruito che uno creato ogni volta, questa parte non sono sicuro di quanto il compilatore deduca e ottimizzi, potrebbe esserci un difetto qui.

In ogni caso, sembra che l'uso di un'istruzione switch, con o senza internare prima la stringa, dia all'incirca gli stessi risultati della semplice istruzione or, che è prevedibile, mentre l'array-lookup è molto più costoso, che anche per me era previsto.

Armeggia con il codice e correggilo (o commentalo) se ci sono problemi.

Ed ecco il codice sorgente, piuttosto lungo:

using System;
using System.Linq;
using System.Diagnostics;
namespace StackOverflow826081
{
    class Program
    {
        private const Int32 ITERATIONS = 1000000;
        static void Main()
        {
            String a;
            String[] ops = CreateArray();
            Int32 count;
            Stopwatch sw = new Stopwatch();
            Int32 pass = 0;
            Action<String, Int32> report = delegate(String title, Int32 i)
            {
                if (pass == 2)
                    Console.Out.WriteLine(title + ": " + sw.ElapsedMilliseconds + " ms");
            };

            for (pass = 1; pass <= 2; pass++)
            {
                #region || operator

                a = "a";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (a == "b" || a == "c")
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("||, not found", count);
                sw.Reset();

                a = "b";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (a == "b" || a == "c")
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("||, found", count);
                sw.Reset();

                #endregion

                #region array.Contains

                a = "a";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (ops.Contains(a))
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("array.Contains, not found", count);
                sw.Reset();

                a = "b";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (ops.Contains(a))
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("array.Contains, found", count);
                sw.Reset();

                #endregion           

                #region array.Contains

                a = "a";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (CreateArray().Contains(a))
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("array.Contains, inline array, not found", count);
                sw.Reset();

                a = "b";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (CreateArray().Contains(a))
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("array.Contains, inline array, found", count);
                sw.Reset();

                #endregion

                #region switch-statement

                a = GetString().Substring(0, 1); // avoid interned string
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    switch (a)
                    {
                        case "b":
                        case "c":
                            count++;
                            break;
                    }
                }
                sw.Stop();
                report("switch-statement, not interned, not found", count);
                sw.Reset();

                a = GetString().Substring(1, 1); // avoid interned string
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    switch (a)
                    {
                        case "b":
                        case "c":
                            count++;
                            break;
                    }
                }
                sw.Stop();
                report("switch-statement, not interned, found", count);
                sw.Reset();

                #endregion                      

                #region switch-statement

                a = "a";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    switch (a)
                    {
                        case "b":
                        case "c":
                            count++;
                            break;
                    }
                }
                sw.Stop();
                report("switch-statement, interned, not found", count);
                sw.Reset();

                a = "b";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    switch (a)
                    {
                        case "b":
                        case "c":
                            count++;
                            break;
                    }
                }
                sw.Stop();
                report("switch-statement, interned, found", count);
                sw.Reset();

                #endregion
            }
        }

        private static String GetString()
        {
            return "ab";
        }

        private static String[] CreateArray()
        {
            return new String[] { "b", "c" };
        }
    }
}

Altri suggerimenti

Bene, il più vicino a quello che puoi ottenere è:

switch (a) {
   case "b":
   case "c":
      // variable a is either "b" or "c"
      break;
}

Per quanto ne so, non è un'opzione.

Puoi usare le espressioni regolari:

if(Regex.IsMatch(a, "b|c"))

Se il contenuto di " a " può essere più lungo di un personaggio usare questo:

if(Regex.IsMatch(a, "^(b|c)<*>quot;))

No, non con quella sintassi. Ma ci sono molte opzioni per codificarlo.

if ("bc".Contains(a)) { } // Maybe check a.Length == 1, too.

if ((a[0] & 0x62) == 0x62) { } // Maybe check a.Length == 1, too.

if (new String[] { "b", "c" }.Contains(a)) { }

Forse potresti sovraccaricare l'operatore e far funzionare la sintassi, ma questo dipende davvero da ciò che vuoi ottenere ed è difficile da dire dal tuo semplice esempio.

È possibile in determinate situazioni. Vale a dire, enumerazioni contrassegnate:

[Flags]
enum MyEnum {
    None = 0,
    A = 1,
    B = 2,
    C = 4,
    D = 8
}

//...

MyEnum a = MyEnum.B

if((a & (MyEnum.B | MyEnum.C)) > 0)
    // do something

è equivalente a:

if((a & MyEnum.B) > 0 || (a & MyEnum.C) > 0)
    // do something

La ragione di ciò ha a che fare con le maschere di bit. In binario,

None = 00000
A    = 00001
B    = 00010
C    = 00100
D    = 01000

Quindi quando usiamo il | operatore, facciamo un confronto bit per bit alla ricerca di 1 nella colonna e li copiamo nel risultato. Se non ci sono 1 nella colonna, si copia uno 0.

  B 00010
& C 00100
---------
    00110

Quindi quando applichiamo & amp; operatore, cerchiamo 1 in tutte le righe di ogni colonna prima di copiare un 1.

  (B & C) 00110
& (a = B) 00010
---------------
          00010

Che è > 0, restituendo quindi true.

Stranamente, questo è il modo più efficiente per farlo, dal momento che ti salva un confronto numerico (>) e un operatore logico (||), che fa tutto quel cortocircuito di fantasia e quant'altro.

No, non è così che l'operatore o (||) funziona in C #.

Una soluzione alternativa, sebbene renda il codice meno leggibile, è quella di creare una funzione che controlli il valore desiderato, qualcosa di simile a:

public static bool Any(object a, params object[] b)
{
    foreach(object item in b)
    {
        if(a == b)
        {
            return true;
        }
    }
    return false;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top