tags:

views:

242

answers:

2

As far as performance is concerned, Which way is better Linq Select Query or For Loop to search something in generic List?

+5  A: 

A for loop may well be very slightly faster. Measure it to find out for sure... but then look at the readability. (EDIT: When you measure it, try doing so for rather longer than the benchmark in the accepted answer does. Also compare the time taken for this piece of code with the time for the rest of your program. Is this really a bottleneck?)

I wouldn't usually use a "select" unless you actually need to project a sequence of results though. To find a single element, either use:

list.Find(x => x.Name == "Foo");

or

list.FirstOrDefault(x => x.Name == "Foo");

I believe both of these are significantly more readable than the corresponding for loop. If you're just looking for an object then you might want to consider using a HashSet<T> instead or in combination with the list.

EDIT: Here's a benchmark to test it. Code is below results.

c:\Users\Jon\Test>test 1000000 500000 1000
FindCustomerLinq: 28531
FindCustomerListFind: 12315
FindCustomerForLoop: 9737
FindCustomerForEachLoop: 14743

So that's looking in a list of a million elements, finding one half way through it, but doing it 1000 times. So yes, the for loop is actually three times as fast... but you'd have to be doing this an awful lot before this difference actual becomes significant. If you're doing this kind of thing that much, you should look for other options such as a Dictionary.

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

public class Customer
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string Phone { get; set; }
}

class Test
{
    static void Main(string[] args)
    {
        int size = int.Parse(args[0]);
        int id = int.Parse(args[1]);
        int iterations = int.Parse(args[2]);

        var list = new List<Customer>(size);
        for (int i=0; i < size; i++)
        {
            list.Add(new Customer {
                ID = i, 
                Address = "Address " + i,
                Name = "Cusomer Name " + i,
                Phone= "Phone " + i,
            });
        }

        Time(FindCustomerLinq, list, id, iterations);
        Time(FindCustomerListFind, list, id, iterations);
        Time(FindCustomerForLoop, list, id, iterations);
        Time(FindCustomerForEachLoop, list, id, iterations);
    }

    static void Time(Func<List<Customer>, int, Customer> action,
                     List<Customer> list,
                     int id, int iterations)
    {
        Stopwatch sw = Stopwatch.StartNew();
        for (int i=0; i < iterations; i++)
        {
            action(list, id);
        }
        sw.Stop();
        Console.WriteLine("{0}: {1}", action.Method.Name, (int) sw.ElapsedMilliseconds);
    }

    static Customer FindCustomerLinq(List<Customer> customers, int id)
    {
        return customers.FirstOrDefault(c => c.ID == id);
    }

    static Customer FindCustomerListFind(List<Customer> customers, int id)
    {
        return customers.Find(c => c.ID == id);
    }

    static Customer FindCustomerForLoop(List<Customer> customers, int id)        
    {
        for (int i=0; i < customers.Count; i++)
        {
            if (customers[i].ID == id)
            {
                return customers[i];
            }
        }
        return null;
    }

    static Customer FindCustomerForEachLoop(List<Customer> customers, int id)
    {
        foreach (Customer c in customers)
        {
            if (c.ID == id)
            {
                return c;
            }
        }
        return null;
    }
}
Jon Skeet
+1  A: 

Some days before i tried same thing as R&D for 50000 Records and found that for loop takes approx 60% time as the time taken by linq where clause

Elapsed time for Linq : 87 ms Elapsed time for Linq : 48 ms

Elapsed time for Linq : 143 ms Elapsed time for Linq : 76 ms

and so on.. for details please see the code how i did it

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace SearchingList
{
    public partial class Form1 : Form
    {
        private int searchingID = 0;
        public int SearchingID 
        {
            get
            {       
                if (string.IsNullOrEmpty(txtID.Text))
                    searchingID = 0;
                else
                    int.TryParse(txtID.Text, out searchingID);
                return searchingID;
            }
            set
            {
                SearchingID = searchingID;
            }
        }
        public Form1()
        {
            InitializeComponent();
        }

        private void btnsearch_Click(object sender, EventArgs e)
        {
            List<Customer> lstcustomersFound = new List<Customer>();
            Stopwatch stp = new Stopwatch();
            stp.Start();
            lstcustomersFound = GetSearchedCustomersByLinq(SearchingID, (List<Customer>)dgvAllData.DataSource);
            stp.Stop();
            lblLinq.Text = "Elapsed Time Linq : " + stp.ElapsedMilliseconds.ToString() + " ms";
            stp.Start();
            lstcustomersFound = GetSearchedCustomersByForLoop(SearchingID, (List<Customer>)dgvAllData.DataSource);
            stp.Stop();
            lblFor.Text ="Elapsed Time for loop : " + stp.ElapsedMilliseconds.ToString() + " ms";
            dgvSearched.DataSource = lstcustomersFound;
        }

        private List<Customer> GetSearchedCustomersByForLoop(int searchingID, List<Customer> lstcustomers)
        {
            List<Customer> lstcustomersFound = new List<Customer>();
            foreach (Customer customer in lstcustomers)
            {
                if (customer.CusomerID.ToString().Contains(searchingID.ToString()))
                {
                    lstcustomersFound.Add(customer);
                }
            }
            return lstcustomersFound;
        }

        private List<Customer> GetSearchedCustomersByLinq(int searchingID, List<Customer> lstcustomers)
        {
            var query = from customer in lstcustomers
                        where customer.CusomerID.ToString().Contains(searchingID.ToString())
                        select customer as Customer;
            return query.ToList();
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            List<Customer> customers = new List<Customer>();
            Customer customer;
            for (int id = 1; id <= 50000; id++)
            {
                customer = new Customer();
                customer.CusomerAddress = "Address " + id.ToString();
                customer.CusomerID = id;
                customer.CusomerName = "Cusomer Name " + id.ToString(); 
                customer.CusomerPhone= "Phone " + id.ToString();
                customers.Add(customer);
            }
            dgvAllData.DataSource = customers;
        }

    }
}

Customer Class

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

namespace SearchingList
{
    public class Customer
    {
        public int CusomerID { get; set; }
        public string CusomerName { get; set; }
        public string CusomerAddress { get; set; }
        public string CusomerPhone { get; set; }
    }
}

As performance is consideration i will go for For Loop instead of Linq

Jaswant Agarwal
That's *copying* a list rather than finding a specific entry. I'd also argue that you're measuring for *way* too short a time for those results to be meaningful. Your condition is also very suspicious - looking for "10" will find "100" for example... and why convert the searchingID to a string on every iteration in the loop? I know you're doing the same thing in both cases, but even so I wouldn't use this as a good benchmark.
Jon Skeet
I'm probably missing something, but don't you have to reset that Stopwatch somewhere?
Svish
I would also say that I have to agree with Jon Skeet...
Svish
I created one more program not posted here , where customerId was an string and serched result can be populated based on text changed in customer id text box..and performance result was almost same
Jaswant Agarwal