Répondre
Non, vous pouvez le faire:
if (new[] { "b", "c" }.Contains(a))
si vous avez les LINQ extensions disponibles, mais c'est à peine une amélioration.
En réponse au commentaire sur la performance, voici un code temporel de base. Notez que le code doit être regardé avec un oeil critique, j'aurais pu faire des choses ici qui faussent les timings.
Les premiers résultats:
||, 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
Tout le code a été exécuté deux fois, et seulement passer nr. 2 a été signalé, pour éliminer les frais généraux JITting de l'équation. Les deux passages exécutaient chaque type de vérification un million de fois, et l'exécutaient tous deux où l'élément à trouver était l'un des éléments pour le trouver (c'est-à-dire que l'instruction if exécuterait son bloc) et une fois l'élément (le bloc ne serait pas exécuté). Les horaires de chacun sont signalés. J'ai testé à la fois un tableau pré-construit et un qui est construit à chaque fois, cette partie je ne sais pas combien le compilateur déduit et optimise loin, il pourrait y avoir un défaut ici. Dans tous les cas, il semble que l'utilisation d'une instruction switch, avec ou sans internement de la chaîne, donne à peu près les mêmes résultats que la simple ou-instruction, ce qui est normal, alors que la recherche de tableau est beaucoup plus plus coûteux, ce qui pour moi était également attendu.
S'il vous plaît bricoler avec le code, et corriger (ou commenter) s'il y a des problèmes.
Et voici le code source, assez longue:
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" };
}
}
}
Si le tableau est alloué de façon statique, le test de performance peut être intéressant (si le temps pris par l'expression est suffisamment long pour être mesuré par rapport au temps système). – Richard
A ma connaissance qui n'est pas une option.
Eh bien, le plus proche de ce que vous pouvez obtenir est:
switch (a) {
case "b":
case "c":
// variable a is either "b" or "c"
break;
}
La réponse acceptée est moins de code, mais en utilisant une instruction switch a moins de frais généraux je crois. –
Je recommande cette solution à la place. D'abord, c'est plus lisible. Deuxièmement, il a moins de frais généraux. Troisièmement, si la logique doit changer à l'avenir, il est plus facile à maintenir. –
La réponse acceptée peut être plus agréable sur une seule ligne, mais celle-ci n'alloue pas de mémoire supplémentaire pour un tableau. – Kon
Non, pas avec cette syntaxe. Mais il y a beaucoup d'options pour coder cela.
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)) { }
Peut-être que vous pourriez faire une surcharge d'opérateur et obtenir votre travail de syntaxe, mais cela dépend vraiment de ce que vous voulez atteindre et il est difficile de dire de votre exemple simple.
Non, ce n'est pas ainsi que fonctionne l'opérateur or (||) en C#.
Une solution alternative, mais il rend le code moins lisible, est de créer une fonction qui vérifie la valeur que vous voulez, quelque chose de similaire à:
public static bool Any(object a, params object[] b)
{
foreach(object item in b)
{
if(a == b)
{
return true;
}
}
return false;
}
Vous pouvez utiliser des expressions régulières:
if(Regex.IsMatch(a, "b|c"))
Si le contenu de « un » peut être plus d'une utilisation de caractères ceci:
if(Regex.IsMatch(a, "^(b|c)$"))
Y Vous pouvez dans certaines situations. A savoir, battant pavillon énumérations:
[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
équivaut à:
if((a & MyEnum.B) > 0 || (a & MyEnum.C) > 0)
// do something
La raison doit faire avec des masques de bits. En binaire,
None = 00000
A = 00001
B = 00010
C = 00100
D = 01000
Donc, lorsque nous utilisons le | opérateur, nous effectuons une comparaison bit par bit à la recherche de 1 dans la colonne et les copions dans le résultat. S'il n'y a pas 1 dans la colonne, vous copiez un 0.
B 00010
& C 00100
---------
00110
Ensuite, lorsque nous appliquons l'opérateur &, nous recherchons 1 dans toutes les lignes de chaque colonne avant de copier un 1.
(B & C) 00110
& (a = B) 00010
---------------
00010
Qui est> 0, rendant ainsi vrai. Bizarrement, c'est la façon la plus efficace de le faire, car elle vous évite une comparaison numérique (>) et un opérateur logique (||), qui fait tout ce qui court de court-circuit fantaisie et autres joyeusetés.
Etes-vous sûr de vouloir utiliser | opérateur (binaire ou) au lieu de || (logique ou)? –
... vous ne voulez pas dire || opérateur? –
correct! J'ai édité le post. –