Performance "where in foreach vs if"

4

Which of the cases would perform best?

var chaves = new list<string>();
foreach(var item in lista)
{
   if(!string.IsNullOrEmpty(item.Chave))
   {
      chaves.Add(item.Chave);
   }
}

Or

listaValida = lista.Where(x => !string.IsNullOrEmpty(x.Chave));
foreach(var item in listaValida)
{
    chaves.Add(item.Chave);
}

Is there a performance difference between the two cases?

    
asked by anonymous 13.04.2017 / 17:13

3 answers

6

The 1 code was faster (though I find it much uglier to read) Here's what I used to test

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace SpeedTest
{
    public class ItemChave
    {
        public string Chave { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {

            List<ItemChave> lista = new List<ItemChave>();
            lista.Add(new ItemChave() { Chave = "a" });
            lista.Add(new ItemChave() { Chave = "b" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "c" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "d" });
            lista.Add(new ItemChave() { Chave = "a" });
            lista.Add(new ItemChave() { Chave = "b" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "c" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "d" });
            lista.Add(new ItemChave() { Chave = "a" });
            lista.Add(new ItemChave() { Chave = "b" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "c" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "d" });
            lista.Add(new ItemChave() { Chave = "a" });
            lista.Add(new ItemChave() { Chave = "b" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "c" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "d" });
            lista.Add(new ItemChave() { Chave = "a" });
            lista.Add(new ItemChave() { Chave = "b" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "c" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "d" });
            lista.Add(new ItemChave() { Chave = "a" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "c" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "d" });
            lista.Add(new ItemChave() { Chave = "a" });
            lista.Add(new ItemChave() { Chave = "b" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "c" });
            lista.Add(new ItemChave() { Chave = "" });
            lista.Add(new ItemChave() { Chave = "d" });



            Stopwatch sw = new Stopwatch();
            sw.Start();
            var chaves = new List<string>();
            foreach (var item in lista)
            {
                if (!string.IsNullOrEmpty(item.Chave))
                {
                    chaves.Add(item.Chave);
                }
            }
            sw.Stop();
            Console.WriteLine("Tempo 1 ={0}", sw.Elapsed);

            Stopwatch sw2 = new Stopwatch();
            sw2.Start();

            var listaValida = lista.Where(x => !string.IsNullOrEmpty(x.Chave));
            foreach (var item in listaValida)
            {
                chaves.Add(item.Chave);
            }
            sw2.Stop();
            Console.WriteLine("Tempo 2 ={0}", sw2.Elapsed);
            Console.ReadKey();

        }
    }
}
    
13.04.2017 / 17:15
6

The right answer is: it depends.

Jbueno has already explained how works in case your list was created based on data available only in the memory space of the application , ie: that your application mounted alone.

However! LINQ can also be used to get data from a database if you want to completely abstract yourself from the SQL language.

If your list was loaded in real time from a database, Entity Framework , the situation would be quite different.

In this case:

var chaves = new list<string>();
foreach(var item in lista)
{
    if(!string.IsNullOrEmpty(item.Chave))
    {
       chaves.Add(item.Chave);
    }
}

You may have made the equivalent of a SELECT without WHERE , which can load millions of records into memory. Hence you select the records that interest you in C #. It could be a waste of resources.

In this case:

listaValida = lista.Where(x => !string.IsNullOrEmpty(x.Chave));
foreach(var item in listaValida)
{
    chaves.Add(item.Chave);
}

LINQ generates a SQL statement something like this:

SELECT * FROM tabela WHERE chave is not null AND LEN(chave) > 0

This way you can potentially avoid the load and transit of millions of record. This would undoubtedly be faster for most cases.

In both cases, if you use the .ToList() method your code gets cleaner.

    
13.04.2017 / 17:43
5

There is not much mystery. Without knowing the details of how the language works, it is only measuring and averaging to have a basis of which is faster.

In my tests, with three million records, the first case was faster (% with%), taking an average of 40ms for each execution, the second (% with%) averaged 55ms per run.

Using Caso1() ( Caso2() ) each execution took an average of 90ms.

The code I used to test was this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;

public class Program 
{
    static List<string> lista = new List<string>();
    public static void Main (string[] args)
    {
        PopularLista();

        Console.WriteLine(lista.Count);

        Caso1();
        Caso2();
        Caso3();
    }

    private static void Caso1()
    {
        var watch = Stopwatch.StartNew();

        var chaves = new List<string>();
        foreach(var item in lista)
        {
            if(!string.IsNullOrEmpty(item))
            {
                chaves.Add(item);
            }
        }

        watch.Stop();
        var ms = watch.ElapsedMilliseconds;
        Console.WriteLine("Caso 1: " + ms + " ms");
    }

    private static void Caso2()
    {
        var watch = Stopwatch.StartNew();

        var chaves = new List<string>();
        var listaValida = lista.Where(x => !string.IsNullOrEmpty(x));
        foreach(var item in listaValida)
        {
            chaves.Add(item);
        }

        watch.Stop();
        var ms = watch.ElapsedMilliseconds;
        Console.WriteLine("Caso 2: " + ms + " ms");
    }

    private static void Caso3()
    {
        var watch = Stopwatch.StartNew();

        var listaValida = lista.Where(x => !string.IsNullOrEmpty(x)).ToList();   

        watch.Stop();
        var ms = watch.ElapsedMilliseconds;
        Console.WriteLine("Caso 3: " + ms + " ms");
    }

    private static void PopularLista()
    {
        for(int i = 0; i < 3000000; i++)
            lista.Add(i % 2 == 0 ? "Teste" : "");
    }
}

You can run the tests on repl.it.

    
13.04.2017 / 17:31