Если я полностью понимаю, что вы пытаетесь сделать, я не думаю, что я буду полагаться исключительно на встроенные операторы LINQ. Я думаю (акцент на мысли), что любая комбинация встроенных операторов LINQ собирается решить эту проблему в O (n^2) времени исполнения.
Если бы я собирался осуществить это в LINQ, то я хотел бы создать метод расширения для IEnumerable, который похож на Scan
функции в реактивных расширений (или найти библиотеку, что там уже реализовали):
public static class EnumerableExtensions
{
public static IEnumerable<TAccumulate> Scan<TSource, TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> accumulator)
{
// Validation omitted for clarity.
foreach(TSource value in source)
{
seed = accumulator.Invoke(seed, value);
yield return seed;
}
}
}
Тогда это должно сделать это вокруг O (п § п) (из-за заказа по операциям):
leaveDetails
.OrderBy(x => x.LeaveType)
.ThenBy(x => x.Year)
.Scan(new {
Year = 0,
LeaveType = "Seed",
LeaveTaken = 0,
LeaveAllocation = 0.0,
LeaveCarriedOver = 0.0,
RunningTotal = 0.0
},
(acc, x) => new {
x.Year,
x.LeaveType,
x.LeaveTaken,
x.LeaveAllocation,
x.LeaveCarriedOver,
RunningTotal = x.LeaveCarriedOver + (acc.LeaveType != x.LeaveType ? 0 : acc.RunningTotal)
});
Вы не говорите, но я предполагаю, что данные поступают из базы данных; если это так, то вы можете получить leaveDetails
назад уже отсортировано и пропустить сортировку здесь. Это приведет вас к O (n).
Если вы не хотите создавать метод расширения (или найдите его), то это приведет к тому же (просто уродливым способом).
var temp = new
{
Year = 0,
LeaveType = "Who Cares",
LeaveTaken = 3,
LeaveAllocation = 0.0,
LeaveCarriedOver = 0.0,
RunningTotal = 0.0
};
var runningTotals = (new[] { temp }).ToList();
runningTotals.RemoveAt(0);
foreach(var l in leaveDetails.OrderBy(x => x.LeaveType).ThenBy(x => x.Year))
{
var s = runningTotals.LastOrDefault();
runningTotals.Add(new
{
l.Year,
l.LeaveType,
l.LeaveTaken,
l.LeaveAllocation,
l.LeaveCarriedOver,
RunningTotal = l.LeaveCarriedOver + (s == null || s.LeaveType != l.LeaveType ? 0 : s.RunningTotal)
});
}
Это также должно быть O (N журнал N) или O (п), если вы можете предварительно сортировать leaveDetails
.
Возможно, вы можете использовать метод Aggregate из LINQ: https://msdn.microsoft.com/en-us/library/system.linq.enumerable.aggregate.aspx. Это эквивалентно сгибанию функционального программирования. –
Я расскажу вам, как это решить. Вы можете сделать это, получив «отдельный» <»« Список> 'of Year (' int') и LeaveType (я предполагаю, что это 'string'). Чтобы получить это, вам следует предоставить простой «Distinct <>», за которым следует «Выбрать <>». Затем этот список - это сумма, которую вы можете фактически накапливать. Теперь, используя этот новый список, вам нужно сделать 'Select <>' и вернуть новый объект, поэтому давайте скажем 'Tuple ', где первый параметр 2 совпадает с другим списком, но последний int you нужен список деталей с 'Where <> 'для фильтрации для year/leavetype, а затем возвращаем' Sum <> 'этого. –
Franck
@Franck ваш комментарий имеет смысл для меня, но я просто не получаю права с моим запросом linq. Можете ли вы отправить ответ на эту тему. благодаря – mboko