Linq in foreach with c# Im running a photocontest and making a list of winners with one winner each day. My loop is running very slow. It seams to be the toList() that is time consuming. Any suggestions on how to make it run faster?

foreach (var date in dates)
        {

            var voteList = _images.Select(image =&gt; new ImageWinnerVotes
                                                   {
                                                       ID = image.ID,
                                                       Image = image.ImagePath,
                                                       Thumbnail = image.ThumbnailImagePath,
                                                       Title = image.Name,
                                                       Url = GetFriendlyUrl(image.ID),
                                                       Date = image.CreatedDate,
                                                       WinnerDateString = date.Date.ToString("dd/MM"),
                                                       WinnerDate = date.Date,
                                                       TotalVotes =
                                                           (votes.Where(vote =&gt; vote.ItemId == image.ID)).Count(),
                                                       Name = image.Fields["Name"].ToString(),
                                                       Votes =
                                                           (votes.Where(
                                                               vote =&gt;
                                                               vote.ItemId == image.ID &amp;&amp;
                                                               vote.Date.DayOfYear == date.Date.DayOfYear)).Count()
                                                   }).ToList();

            voteList = voteList.OrderByDescending(v =&gt; v.Votes).ToList();

            var j = 0;
            var findingWinner = true;

            while(findingWinner)
            {
                var inWinnersList = false;
                if (winnersList.Count() != 0)
                {
                    if(!winnersList.Contains(voteList.ElementAt(j)))
                    {
                        winnersList.Add(voteList.ElementAt(j));
                        findingWinner = false;
                    }
                }
                else
                {
                    winnersList.Add(voteList.ElementAt(j));
                    findingWinner = false;
                }

                j++;
            }

        }
First up calls to .ToList() are not inherently slow - it's only when each element in the list is slow to compute that .ToList() appears slow.

So then, what makes the time to compute each element slow?

Well, you're querying votes twice in each query - and computing TotalVotes for each iteration of the foreach loop.

After the query you are then sorting all the candidates by daily votes and then searching through the candidates and picking the first candidate image that hasn't previously won. The search for the winner uses Count, Contains, and ElementAt - all of which can cause the list to be enumerated each time.

All of this is surrounded by a foreach loop to iterate through each date.

Lots of nested iterating - and most of which is unnecessary.

I've got a solution which I've timed to be 135 times faster.

Here it is:

var query =
    from image in _images
    join tvote in votes on image.ID equals tvote.ItemId into tvs
    let TotalVotes = tvs.Count()
    join vote in votes on image.ID equals vote.ItemId
    join date in dates on vote.Date.DayOfYear equals date.Date.DayOfYear    
    group vote by new
    {
        image,
        date.Date,
        TotalVotes,
    } into dvs
    let Date = dvs.Key.Date
    let Image = dvs.Key.image
    let DailyVotes = dvs.Count()
    orderby DailyVotes descending
    orderby Date
    group new
    {
        Image = dvs.Key.image,
        dvs.Key.TotalVotes,
        DailyVotes = dvs.Count(),
    } by Date;


var winners = query.Aggregate(new ImageWinnerVotes[] { }, (iwvs, gs) =&gt;
{
    var previousWinners = iwvs.Select(iwv =&gt; iwv.ID).ToArray();
    var winner = gs
        .Where(g =&gt; !previousWinners.Contains(g.Image.ID))
        .Select(g =&gt; new ImageWinnerVotes
        {
            ID = g.Image.ID,
            Image = g.Image.ImagePath,
            Thumbnail = g.Image.ThumbnailImagePath,
            Title = g.Image.Name,
            Url = GetFriendlyUrl(g.Image.ID),
            Date = g.Image.CreatedDate,
            WinnerDateString = gs.Key.ToString("dd/MM"),
            WinnerDate = gs.Key,
            TotalVotes = g.TotalVotes,
            Name = g.Image.Fields["Name"].ToString(),
            Votes = g.DailyVotes,
        })
        .FirstOrDefault();
    return winner == null ? iwvs.ToArray() : iwvs.Concat(new [] { winner, }).ToArray();
}).ToArray();


This is purely a LINQ solution. It's a good idea not to mix LINQ &amp; non-LINQ.

Now, if you didn't have the requirement to eliminate previous winners then I have a solution that is twice as fast again:

var query =
    from image in _images
    join tvote in votes on image.ID equals tvote.ItemId into tvs
    let TotalVotes = tvs.Count()
    join vote in votes on image.ID equals vote.ItemId
    join date in dates on vote.Date.DayOfYear equals date.Date.DayOfYear    
    group vote by new
    {
        image,
        date.Date,
        TotalVotes,
    } into dvs
    group new
    {
        Image = dvs.Key.image,
        dvs.Key.TotalVotes,
        DailyVotes = dvs.Count(),
        } by dvs.Key.Date into gxs
    let winners =
        from x in gxs
        orderby x.DailyVotes descending
        select x
    let winner = winners.First()
    let image = winner.Image
    let winnerDate = gxs.Key
    orderby winnerDate
    select new ImageWinnerVotes
    {
        ID = image.ID,
        Image = image.ImagePath,
        Thumbnail = image.ThumbnailImagePath,
        Title = image.Name,
        Url = GetFriendlyUrl(image.ID),
        Date = image.CreatedDate,
        WinnerDateString = winnerDate.ToString("dd/MM"),
        WinnerDate = winnerDate,
        TotalVotes = winner.TotalVotes,
        Name = image.Fields["Name"].ToString(),
        Votes = winner.DailyVotes,
    };

var winners = query.ToArray();


Let me know if these help and/or if you need more info.