As far as performance is concerned, Which way is better Linq Select Query or For Loop to search something in generic List?
views:
242answers:
2A 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;
}
}
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