Karthick
Karthick

Reputation: 129

Foreach Loop took more time to process

I have two collections and some conditions are done using linq query. Comparing two lists and getting result from that. I have used foreach loop and linq query, the collections have 65 thousand datas, my problem is it tooks more time to process. My code is mentioned below. How to improve the performance and how to reduce the processing time. If any idea to improve the performance please share.

foreach (var part in quoteParts)
{                            
    var presentPart = existingPart.FirstOrDefault(p => p.PartName == part.PartNumber);

    if (presentPart != null)
    {
        int partID = presentPart.ID;
        string partNumber = Convert.ToString(presentPart.PartName);

        foreach (var quotesPart in quoteStepInProcesses)
        {
            var presentStepInProcess = existingStepInProcesses.FirstOrDefault(p => p.ProcessId == quotesPart.StepInProcessID && quotesPart.PartNumber == partNumber); 

            if (presentStepInProcess != null)
            {
                PartProcesses.Add(new PartProcessDto
                {
                    ProcessName = Convert.ToString(presentStepInProcess.ID),
                    PartName = Convert.ToString(presentPart.ID)
                });
            }
        }
    }
}

Upvotes: 0

Views: 92

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1064204

You have at least two places where you're using FirstOrDefault inside a loop to locate a record. The first thing I'd try would be pre-indexing that data; for example:

var partsByName = existingPart.ToDictionary(x => x.PartName);
foreach (var part in quoteParts)
{
    if(partsByName.TryGetValue(part.PartNumber, out var presentPart))
    {
        // ...
    }
}

and similarly with existingStepInProcesses via ProcessId. Also note that the second test in your innermost FirstOrDefault (&& quotesPart.PartNumber == partNumber) doesn't actually filter p, so should be moved away from that lookup. So: outside the first loop next to the first ToDictionary:

var processes = existingStepInProcesses.ToDictionary(x => x.ProcessId);

then in the innermost loop:

if (quotesPart.PartNumber == partNumber &&
    processes.TryGetValue(quotesPart.StepInProcessID, out var presentStepInProcess))
{
    // ...
}

You can possibly also do the same with quoteStepInProcesses to remove the second foreach - it depends on how many matches you expect. If there are multiple: maybe .ToLookup instead of ToDictionary.

Upvotes: 9

Related Questions