I'm trying to write a program that has a for
loop, inside of which I have lambda expression to get a certain value. The loop has about 20,000 iterations. Including this lambda expression increases the execution time significantly. If I include it, it takes about 20 mins for the loop to finish; without it, it takes just 10 seconds.
Here's what the lambda expression looks like:
code = countries.Find(c => c.ISO2Code == iso2).Country_Code
Same expression using Linq:
code = (from a in countries
where a.ISO2Code == iso2
select a.Country_Code).First();
Here, the list countries
is cached for the loop starts, so it's not like the query is made to the DB. What's the reason for this time costly expression?
Here's the full code for the loop:
for (int i = 1; i < count - 1; i++)
{
if (!timer.IsRunning)
timer.Start();
var d = line[i];
var row = d.Replace("\n", "");
var values = row.Split(',');
if (values.Length < 3)
{
return;
}
if (values.Length >= 2)
{
if (values[2] != null && values[2] != "")
{
string contactno = Utils.RemoveSpecialCharacters(values[2]);
if (model.NumberFormat == 1)
{
Country cntry =
countries.Where(x => x.Country_Code == model.CountryCode)
.FirstOrDefault();
contactno = utils.GetValidNumberWithCountryCode(contactno, cntry.ISO2Code);
}
int? code = null;
try
{
contactno = "+" + contactno;
try
{
//this is commented
ph = phoneUtil.parseAndKeepRawInput(contactno, "US");
if (phoneUtil.isValidNumber(ph))
{
string iso2 = phoneUtil.getRegionCodeForNumber(ph);
if (!string.IsNullOrEmpty(iso2))
{
code = countries.Find(c => c.ISO2Code == iso2).Country_Code;
//code = (from a in countries
// where a.ISO2Code == iso2
// select a.Country_Code).First();
}
}
}
catch
{
code = null;
}
}
catch
{
}
if (code != null && utils.IsValidNumber(contactno))
{
contactno = utils.GetValidNumber(contactno);
bool match = false;
foreach (var item in existingList)
{
if (item.ContactNumber.ToString() == contactno)
{
ExistingnumberCount += 1;
match = true;
break;
}
}
if (!match)
{
validNumberCount += 1;
Contact_List cl = new Contact_List();
cl.Customer_Code = model.Customer_Code;
try
{
string fname = values[0];
if (fname.Length > 50)
{
fname = fname.Substring(0, 50);
}
cl.First_Name = fname;
}
catch
{
}
try
{
string lname = values[1];
if (lname.Length > 50)
{
lname = lname.Substring(0, 50);
}
cl.Last_Name = lname;
}
catch
{
}
try
{
string CF1 = values[3];
if (CF1.Length > 50)
{
CF1 = CF1.Substring(0, 50);
}
cl.CF1 = CF1;
}
catch
{
}
try
{
string CF2 = values[4];
if (CF2.Length > 50)
{
CF2 = CF2.Substring(0, 50);
}
cl.CF2 = CF2;
}
catch
{
}
try
{
string CF3 = values[5];
if (CF3.Length > 50)
{
CF3 = CF3.Substring(0, 50);
}
cl.CF3 = CF3;
}
catch
{
}
try
{
string CF4 = values[6];
if (CF4.Length > 50)
{
CF4 = CF4.Substring(0, 50);
}
cl.CF4 = CF4;
}
catch
{
}
cl.CountryCode = code;
cl.Contact_No = contactno.Replace("+", "");
cl.Is_Active = true;
cl.Create_Date = DateTime.Now;
cl.Opt_Status_Code = 0;
try
{
string Contact_Email = values[7];
if (Contact_Email.Length > 50)
{
Contact_Email = Contact_Email.Substring(0, 50);
}
cl.Contact_Email = Contact_Email;
}
catch
{
}
}
}
else
{
InvalidnumberCount += 1;
}
}
}
Debug.WriteLine("Total Execution Time: " + (double)(timer.ElapsedMilliseconds / 1000));
Debug.WriteLine("No of iterations completed: " + i);
}
try/catch
blocks there. Why don't you check the indexes before accessing the array or getting the substrings? \$\endgroup\$Where().First()
does not need to find all matches.Where()
constructs a lazy enumerable (and doesn't actually find anything) andFirst()
merely enumerates the first item out of it. As soon as the first item is found, it will stop. There will be some additional overhead compared toFind()
what with the extra objects and method calls involved, but it definitely won't look at more items than it has to. \$\endgroup\$