OU operador em C #
-
05-07-2019 - |
Pergunta
Posso conseguir
if (a == "b" || "c")
em vez de
if (a == "b" || a== "c")
?
Solução
Não, você pode fazer:
if (new[] { "b", "c" }.Contains(a))
Se você tem as extensões LINQ disponíveis, mas que quase uma melhoria.
Em resposta ao comentário sobre o desempenho, aqui está um código de sincronismo básico. Note que o código deve ser vista com um olhar crítico, eu poderia ter feito coisas aqui que distorcer os horários.
Os resultados do primeiro:
||, 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
Todo o código foi executado duas vezes, e só passar nr. 2 foi relatada, para remover JITting cima a partir da equação. Ambos os passes executados cada tipo de cheque de um milhão de vezes, e executaram-no tanto em que o elemento para encontrar foi um dos elementos para encontrá-lo em (isto é, a instrução if iria executar seu bloco), e uma vez que o elemento não foi (o bloco não executar). Os horários de cada é relatado. Eu testei tanto uma matriz pré-construídos e um que é construído a cada vez, esta parte não estou certo quanto os deduz do compilador e otimiza distância, pode haver uma falha aqui.
Em qualquer caso, parece que usando uma opção de declaração, com ou sem internar a corda primeiro, dá mais ou menos os mesmos resultados que o simples ou a declaração, que é de se esperar, enquanto a matriz de pesquisa é muito mais caro, o que para mim também era esperado.
Por favor, mexer com o código e correta (ou comentário)-lo se houver problemas.
E aqui está o código-fonte, bastante longo:
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" };
}
}
}
Outras dicas
Bem, o mais próximo de que você pode obter é:
switch (a) {
case "b":
case "c":
// variable a is either "b" or "c"
break;
}
Para meu conhecimento que não é uma opção.
Você pode usar expressões regulares:
if(Regex.IsMatch(a, "b|c"))
Se o conteúdo de "a" pode ser superior a um uso de caracteres esta:
if(Regex.IsMatch(a, "^(b|c)$"))
Não, não com a sintaxe. Mas há muitas opções para o código que.
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)) { }
Talvez você pudesse fazer alguma sobrecarga de operador e obter o seu trabalho de sintaxe, mas isso realmente depende do que você quer alcançar e é difícil dizer a partir do seu exemplo simples.
Você pode, em determinadas situações. Ou seja, sinalizado enumerações:
[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
A razão para isto tem a ver com máscaras de bits. Em binário,
None = 00000
A = 00001
B = 00010
C = 00100
D = 01000
Assim, quando usamos o | operador, fazemos uma comparação bit-por-bit procurando qualquer 1s na coluna e copiá-los para o resultado. Se não houver 1s na coluna, você copiar um 0.
B 00010
& C 00100
---------
00110
Então, quando nós aplicamos o operador &, olhamos para 1 de em todas as linhas em cada coluna antes de copiar a 1.
(B & C) 00110
& (a = B) 00010
---------------
00010
O que é> 0, retornando assim verdadeiro.
Curiosamente, esta é a maneira mais eficiente de fazê-lo, uma vez que poupa-lhe uma comparação numérica (>) e um operador lógico (||), que faz tudo o que fantasia curto-circuito e outros enfeites.
Não, isto não é como o ou operador (||) trabalha em C #.
Uma solução alternativa, embora ele torna o código menos legível, é criar uma função que verifica o valor desejado, algo semelhante a:
public static bool Any(object a, params object[] b)
{
foreach(object item in b)
{
if(a == b)
{
return true;
}
}
return false;
}