Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Benchmark tests comparing ways of matching a variable against multiple possible options. As created for http://www.mrlacey.com/2017/10/optimizing-comparison-of-variable-with.html
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Linq;
namespace IsOneOfBenchmarks
{
class Program
{
static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<Variations>();
}
}
public class Variations
{
private const MyEnum someVariable = MyEnum.Value3;
readonly MyEnum[] targetValues = { MyEnum.Value1, MyEnum.Value2, MyEnum.Value3, MyEnum.Value6 };
[Benchmark]
public bool MultipleEquals()
{
return someVariable == MyEnum.Value1 || someVariable == MyEnum.Value2 ||
someVariable == MyEnum.Value3 || someVariable == MyEnum.Value6;
}
[Benchmark]
public bool IsOneOfObject()
{
return someVariable.IsOneOf(MyEnum.Value1, MyEnum.Value2, MyEnum.Value3, MyEnum.Value6);
}
[Benchmark]
public bool IsOneOfObjectWithExistingArray()
{
return someVariable.IsOneOf(targetValues);
}
[Benchmark]
public bool IsOneOfGeneric()
{
return someVariable.IsOneOfGeneric<MyEnum>(MyEnum.Value1, MyEnum.Value2, MyEnum.Value3, MyEnum.Value6);
}
[Benchmark]
public bool IsOneOfGenericWithExistingArray()
{
return someVariable.IsOneOfGeneric<MyEnum>(targetValues);
}
[Benchmark]
public bool IsOneOfMyEnum()
{
return someVariable.IsOneOfMyEnum(MyEnum.Value1, MyEnum.Value2, MyEnum.Value3, MyEnum.Value6);
}
[Benchmark]
public bool IsOneOfMyEnumWithExistingArray()
{
return someVariable.IsOneOfMyEnum(targetValues);
}
[Benchmark]
public bool IsOneOfMyEnumNoLinq()
{
return someVariable.IsOneOfMyEnumNoLinq(MyEnum.Value1, MyEnum.Value2, MyEnum.Value3, MyEnum.Value6);
}
[Benchmark]
public bool IsOneOfMyEnumNoLinqWithExistingArray()
{
return someVariable.IsOneOfMyEnumNoLinq(targetValues);
}
}
public static class ArrayExtensions
{
public static bool IsOneOf(this object item, params object[] options)
{
return options.Contains(item);
}
public static bool IsOneOfGeneric<T>(this T item, params T[] options)
{
return options.Contains(item);
}
public static bool IsOneOfMyEnum(this MyEnum item, params MyEnum[] options)
{
return options.Contains(item);
}
public static bool IsOneOfMyEnumNoLinq(this MyEnum item, params MyEnum[] options)
{
for (var i = 0; i < options.Length; i++)
{
if (item == options[0])
{
return true;
}
}
return false;
}
}
public enum MyEnum
{
Value1,
Value2,
Value3,
Value4,
Value5,
Value6,
Value7,
Value8,
Value9,
Value0,
}
}
Owner

mrlacey commented Oct 5, 2017

The results of my running these tests were

                               Method |        Mean |     Error |    StdDev |
------------------------------------- |------------:|----------:|----------:|
                       MultipleEquals |   0.0013 ns | 0.0041 ns | 0.0034 ns |
                        IsOneOfObject | 132.7228 ns | 2.2074 ns | 2.0648 ns |
       IsOneOfObjectWithExistingArray |  93.5959 ns | 1.7975 ns | 1.8459 ns |
                       IsOneOfGeneric |  63.4804 ns | 0.8762 ns | 0.7317 ns |
      IsOneOfGenericWithExistingArray |  58.5615 ns | 0.8739 ns | 0.7747 ns |
                        IsOneOfMyEnum |  64.2691 ns | 1.3435 ns | 1.3195 ns |
       IsOneOfMyEnumWithExistingArray |  58.2238 ns | 0.9457 ns | 0.8383 ns |
                  IsOneOfMyEnumNoLinq |  12.1887 ns | 0.2395 ns | 0.2123 ns |
 IsOneOfMyEnumNoLinqWithExistingArray |   6.2302 ns | 0.0519 ns | 0.0433 ns |

Conclusion
While using multiple equality checks is by far the fastest, I still think writing

if (MyEnum.Value1 || someVariable == MyEnum.Value2 || someVariable == MyEnum.Value3 || someVariable == MyEnum.Value6)
{
    /// do something
}

is far less preferable to

if (someVariable.IsOneOf[MyEnumNoLinq](targetValues))
{
    /// do something
}

Nice article!

I guess though that:

if (item == options[0]) { return true; }

should read:

if (item == options**[i]**) { return true; }

As a side note when it comes to enums, you should give this interesting article a read: https://blogs.msdn.microsoft.com/seteplia/2017/05/17/box-or-not-to-box-that-is-the-question/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment