我有一个函数,该函数需要IEnumerable并执行GroupJoin来构建字符串。用GroupJoin中的一个简单的总和就可以很好地工作。 我需要更改此值,以便不仅将这些值相加,而且还要累加。
我认为我需要在代码行中添加一个Aggregate函数:item.Sum(x => x.Amount)
IEnumerable<Items> items = {.....};
var list = Enumerable.Range(7, 6).Concat(Enumerable.Range(1, 6))
.GroupJoin(
items,
range => range,
item => item.TransactionDate.Value.Month,
(range, item) => string.Concat(
//Example of string output: { t: "03 Jul 2018", y: 44 },
"{ t: \"",
new DateTime(
range > 6 ? 2018 : 2019,
range,
1).ToString("dd MMM yyyy"),
"\", y: ",
item.Sum(x => x.Amount).ToString(),
" }"
))
.ToArray();
当前结果:返回一个字符串,例如:{t:“ 2018年7月1日”,y:3},{t:“ 2018年8月1日”,y:4},{t:“ 2018年9月1日”,y :1}
必需结果:返回一个字符串,其中y处的值是累加的。例如:{t:“ 2018年7月1日”,y:3},{t:“ 2018年8月1日”,y:7},{t:“ 2018年9月1日”,y:8}
答案 0 :(得分:1)
如果可能的话,可以使用汇总。恕我直言,它看起来很可怕,不易理解,难以测试和维护:
TAccumulate聚合(IEnumerable)
IEnumerable<int>
IEnumerable<int>
的序列List<int>
。
// first extract the amounts:
IEnumerable<int> amountTotals = itemsInGroup.Select(item => item.Amount)
// Then aggregate.
.Aggregate(new List<int>() // Seed with empty list
// every iteration: add a new Total to the TAccumulate and return this TAccumulate:
(tAccumulate, newItem) =>
{
tAccumulate.Add(newItem);
return tAccumulate;
})
如果要创建扩展功能,它将看起来更加整洁:
让我们编写一些扩展功能,因此您可以将它们用作类似LINQ的语句。 参见extension methods demystified
将范围值转换为其DateTime字符串表示形式
static string ToDateTimeText(this int rangeValue)
{
return $"t: \"{new DateTime(range > 6 ? 2018 : 2019, range, 1):dd MMM yyyy}\"";
}
将序列转换为整数,然后转换为总计。
例如:序列{3,4,5,10} => {3,7,12,22}
static IEnumerable<int> ToTotals(IEnumerable<int> source)
{
// TODO: exception if source null
// try to get the first element of the input sequence
var enumerator = source.GetEnumerator;
if (enumerator.MoveNext())
{ // first item fetched; yield return first item
int total = enumerator.Current;
yield return total;
// calculate the rest:
while (enumerator.MoveNext())
{ // there is a next item: Calculate total and yield return
total += enumerator.Current;
yield return total;
}
}
// else: empty input sequence empty, output is empty
}
现在有了这些功能,您的groupBy ResultSelector将会很简单:
(rangeValue, itemsWithThisRangeValue) => new
{
Date = rangeValue.ToDateTimeText(),
AmountTotals = itemsWithThisRangeValue
.Select(item => item.Amount)
.ToTotals(),
}
答案 1 :(得分:1)
组联接是解决您的问题的一种好方法,但是我们应该保持可读性(并避免对项目集合进行多次迭代)。
因此,我不会在联接内使用聚合。
var groups = Enumerable.Range(7, 6).Concat(Enumerable.Range(1, 6)).GroupJoin(
items,
m => m,
i => i.TransactionDate.Value.Month,
(m, itemCol) => new { month = m, items = itemCol }); //Create anonymous type with month and items property.
List<string> outputs = new List<string>(); //Contains your output
int sum = 0;
foreach (var group in groups) //Iterate the groups
{
sum += group.items.Sum(i => i.Amount);
outputs.Add( //I used string.Format for readability. Does not change functionality
string.Format("{{ t: \"{0}\", y: {1} }}",
new DateTime(group.month > 6 ? 2018 : 2019, group.month, 1).ToString("dd MMM yyyy"),
sum));
}