Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Discussion resulting from this answer has me curious. Which is faster:

someEnumerable.Single(predicate);

or

someEnumerable.Where(predicate).Single();

After all, the first is shorter, more concise, and seems to be purpose-built.

Even ReSharper suggests the former:

enter image description here

I was arguing in the previous post, that they are functionally identical, and should have very similar runtime.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
201 views
Welcome To Ask or Share your Answers For Others

1 Answer

LINQ-to-Objects

Nothing answers a question like this like a benchmark:

(Updated)

class Program
{
    const int N = 10000;
    volatile private static int s_val;

    static void DoTest(IEnumerable<int> data, int[] selectors) {
        Stopwatch s;

        // Using .Single(predicate)
        s = Stopwatch.StartNew();
        foreach (var t in selectors) {
            s_val = data.Single(x => x == t);
        }
        s.Stop();
        Console.WriteLine("   {0} calls to Single(predicate) took {1} ms.",
            selectors.Length, s.ElapsedMilliseconds);

        // Using .Where(predicate).Single()
        s = Stopwatch.StartNew();
        foreach (int t in selectors) {
            s_val = data.Where(x => x == t).Single();
        }
        s.Stop();
        Console.WriteLine("   {0} calls to Where(predicate).Single() took {1} ms.",
            selectors.Length, s.ElapsedMilliseconds);
    }


    public static void Main(string[] args) {
        var R = new Random();
        var selectors = Enumerable.Range(0, N).Select(_ => R.Next(0, N)).ToArray();

        Console.WriteLine("Using IEnumerable<int>  (Enumerable.Range())");
        DoTest(Enumerable.Range(0, 10 * N), selectors);

        Console.WriteLine("Using int[]");
        DoTest(Enumerable.Range(0, 10*N).ToArray(), selectors);

        Console.WriteLine("Using List<int>");
        DoTest(Enumerable.Range(0, 10 * N).ToList(), selectors);

        Console.ReadKey();
    }
}

Somewhat shockingly, .Where(predicate).Single() wins by a factor of about two. I even ran both cases twice to make sure caching, etc. was not a factor.

1) 10000 calls to Single(predicate) took 7938 ms.
1) 10000 calls to Where(predicate).Single() took 3795 ms.
2) 10000 calls to Single(predicate) took 8132 ms.
2) 10000 calls to Where(predicate).Single() took 4318 ms.

Updated Results:

Using IEnumerable<int>  (Enumerable.Range())
   10000 calls to Single(predicate) took 7838 ms.
   10000 calls to Where(predicate).Single() took 8104 ms.
Using int[]
   10000 calls to Single(predicate) took 8859 ms.
   10000 calls to Where(predicate).Single() took 2970 ms.
Using List<int>
   10000 calls to Single(predicate) took 9523 ms.
   10000 calls to Where(predicate).Single() took 3781 ms.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...