LINQ в цикле foreach в C#


Im работает в фотоконкурсе и составление списка победителей одного победителя каждый день. Мой цикл работает очень медленно. Это швы, чтобы быть в список (), что занимает много времени. Любые предложения о том, как сделать его работать быстрее?

foreach (var date in dates)
        {

            var voteList = _images.Select(image => 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 => vote.ItemId == image.ID)).Count(),
                                                       Name = image.Fields["Name"].ToString(),
                                                       Votes =
                                                           (votes.Where(
                                                               vote =>
                                                               vote.ItemId == image.ID &&
                                                               vote.Date.DayOfYear == date.Date.DayOfYear)).Count()
                                                   }).ToList();

            voteList = voteList.OrderByDescending(v => 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++;
            }

        }


10617
8
задан 29 августа 2011 в 09:08 Источник Поделиться
Комментарии
3 ответа

Первые звонки .Список() сами по себе не ведут медленно - это только тогда, когда каждый элемент в списке является медленным, чтобы вычислить, что .Список() появляется медленно.

Так что то, что делает время, чтобы вычислить каждый элемент медленно?

Ну, вы запрашиваете голоса дважды в каждом запросе - и вычислительной TotalVotes для каждой итерации цикла foreach петли.

После выполнения запроса вы после сортировки всех кандидатов на ежедневный голосов, а потом через поиск кандидатов и сбор первого изображения кандидата, который до этого не выиграл. Поиск winner использует Граф, содержит, и ElementAt , все из которых могут привести списка должны быть пронумерованы, каждый раз.

Все это окружено цикле foreach петли, чтобы выполнить итерации через каждый день.

Много вложенных итераций - и большая часть которых излишня.

У меня есть решение, которое я приуроченных к 135 раз быстрее.

Вот это:

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) =>
{
var previousWinners = iwvs.Select(iwv => iwv.ID).ToArray();
var winner = gs
.Where(g => !previousWinners.Contains(g.Image.ID))
.Select(g => 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();

Это чисто решение для LINQ. Это хорошая идея, чтобы не смешивать в LINQ и LINQ на.

Теперь, если у вас не было требованием устранить предыдущих победителей, то у меня есть решение, которое раз в два раза быстрее:

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();

Дайте мне знать, если эти помощь и/или если вам нужна дополнительная информация.

6
ответ дан 1 сентября 2011 в 02:09 Источник Поделиться

У вас есть много итераций там. голосов.Где находятся в полной итерации голосами несчетных, и вы делаете те один раз для каждого изображения. Как уже упоминалось ранее, все в том, что LINQ-запроса является определение запроса, запроса не выполняется до вызова .Список() который является, почему кажется, что время тонет.

Избавить себя от хлопот и кэш ваших голосов результаты:

Tuple<int, int> numberOfVotesPerImageId =
votes.GroupBy(vote => vote.ItemId)
.Select(voteGroup => Tuple.Create(voteGroup.Key, voteGroup.Count()))
.ToArray();

Tuple<int, int, int> numberOfVotesPerImageIdAndDayOfYear =
votes.GroupBy(vote => new { vote.ItemId, vote.Date.DayOfYear })
.Select(voteGroup => Tuple.Create(voteGroup.Key.Item1, voteGroup.Key.Item2, voteGroup.Count()))
.ToArray();

Затем вы выберите будет иметь гораздо меньшее число итераций, так как вы будете иметь эти агрегаты на голоса в матче против атрибут Itemid, где эти кортежи имеют: .Элемент1 == изображения.Идентификатор и второе место № 2 == Дата.Дата.Функции dayofyear, и в первый .Место № 2 == TotalVotes , а вторая .Item3 = Голоса

Кроме того, введен порядок, в первом пункте перед вызовом .Список() , поэтому она не нужно повторить дважды.

Также, вы хотя цикл должен быть цикл for, потому что итератор, вы должны протестировать длина или рисковать из индекса. И в любое время вы видите, если блок вложен в блок if без остатка космоса, это означает, что вы должны изменить свои положения.. на самом деле я бы сделал это (делаешь счетчик и содержит две итерации, когда содержится в одиночку все, что вам нужно) также ваш inWinnersList переменная не используется.. да и .ElementAt другой итерации через список, который делает его O(J), когда списки прямого попадания в индекс массива, который является O(1):

for (int j = 0; j < voteList.Count; j++)
{
inWinnersList = winnersList.Contains(voteList[j]);
if (inWinnersList)
{
continue;
}

winnersList.Add(voteList[j]);
break;
}

Там, наверное, больше вещей мне не хватает, и подробности я не стану, но я думаю, что это хорошее начало для улучшения производительности и читабельности. Как только вы получите эти куски воедино, и другие улучшения, могут стать очевидны, как цель становится яснее.

4
ответ дан 29 августа 2011 в 11:08 Источник Поделиться

В список() выполняет все в выберите-пункт.
Я думаю, что голоса-коллекции, которые вы не quering против, не зная, как это работает, вор производительности.

Попробуйте снова запустить пример без указания голоса-переменной. Если он проходит гладко, то вы знаете, что для оптимизации.

Что дал ты используешь?

2
ответ дан 29 августа 2011 в 09:08 Источник Поделиться