達成できますか
if (a == "b" || "c")
それ以外の
if (a == "b" || a== "c")
?
達成できますか
if (a == "b" || "c")
それ以外の
if (a == "b" || a== "c")
?
さて、あなたが得ることができるものに最も近いものは次のとおりです:
switch (a) {
case "b":
case "c":
// variable a is either "b" or "c"
break;
}
いいえ、できます:
if (new[] { "b", "c" }.Contains(a))
LINQ拡張機能を利用できる場合でも、それはほとんど改善されません。
パフォーマンスに関するコメントに応えて、ここにいくつかの基本的なタイミングコードがあります。コードは批判的な目で見なければならないことに注意してください。私はここでタイミングを歪めるようなことをしたかもしれません。
最初の結果:
||, 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
すべてのコードは2回実行され、nrのみを渡します。方程式からJITtingオーバーヘッドを取り除くために、2が報告されました。両方のパスは、各タイプのチェックを100万回実行し、検索する要素が検索する要素の1つである場合(つまり、ifステートメントがそのブロックを実行する場合)と、要素がない場合の両方で実行しました。 (ブロックは実行されません)。それぞれのタイミングが報告されます。ビルド済みのアレイと毎回ビルドされるアレイの両方をテストしました。この部分では、コンパイラがどれだけ推測して最適化するかがわかりません。ここに欠陥がある可能性があります。
いずれにせよ、最初に文字列をインターンするかどうかに関係なく、switchステートメントを使用すると、予想される単純なorステートメントとほぼ同じ結果が得られますが、配列ルックアップははるかにコストがかかります。私にも期待されていました。
コードをいじって、問題がある場合は修正(またはコメント)してください。
そして、これがかなり長いソースコードです:
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" };
}
}
}
私の知る限り、それは選択肢ではありません。
正規表現を使用できます。
if(Regex.IsMatch(a, "b|c"))
"a" の内容が 1 文字より長くなる可能性がある場合は、次のように使用します。
if(Regex.IsMatch(a, "^(b|c)$"))
いいえ、その構文ではありません。しかし、それをコーディングするための多くのオプションがあります。
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)) { }
演算子のオーバーロードを実行して構文を機能させることができるかもしれませんが、これは実際に何を達成したいかによって異なり、単純な例からはわかりにくいです。
特定の状況ではできます。つまり、フラグ付きの列挙:
[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
と同等です:
if((a & MyEnum.B) > 0 || (a & MyEnum.C) > 0)
// do something
この理由は、ビット マスクに関係しています。バイナリでは、
None = 00000
A = 00001
B = 00010
C = 00100
D = 01000
したがって、 | を使用すると 演算子を使用して、ビットごとの比較を行い、列内の 1 を探して結果にコピーします。列に 1 がない場合は、0 をコピーします。
B 00010
& C 00100
---------
00110
次に & 演算子を適用すると、1 をコピーする前に、各列のすべての行で 1 を探します。
(B & C) 00110
& (a = B) 00010
---------------
00010
これは > 0 であるため、true を返します。
奇妙なことに、これは最も効率的な方法です。数値比較 (>) と論理演算子 (||) を節約できるため、凝った短絡などをすべて行うことができます。
いいえ、これは C# での or 演算子 (||) の動作ではありません。
別の解決策は、コードが読みにくくなりますが、必要な値をチェックする関数を作成することです。次のようなものです。
public static bool Any(object a, params object[] b)
{
foreach(object item in b)
{
if(a == b)
{
return true;
}
}
return false;
}