c#linq报表用于计算12个月的余额
我想画一张弗洛特图表。我希望x轴是一月到十二月的月份,y轴是账户余额。我有12个月的账户收入和支出,但减去它们只会得到当月的差额,而不会增加上个月的余额 以下是我如何获得该范围内的收入和支出:c#linq报表用于计算12个月的余额,c#,linq,flot,C#,Linq,Flot,我想画一张弗洛特图表。我希望x轴是一月到十二月的月份,y轴是账户余额。我有12个月的账户收入和支出,但减去它们只会得到当月的差额,而不会增加上个月的余额 以下是我如何获得该范围内的收入和支出: var monthsToDate = Enumerable.Range(1, 12) .Select(m => new DateTime(DateTime.Today.Year, m, 1))
var monthsToDate = Enumerable.Range(1, 12)
.Select(m => new DateTime(DateTime.Today.Year, m, 1))
.ToList();
var sums = from month in monthsToDate
select new
{
month = month,
income = (from account in household.Accounts
from transaction in account.Transactions
where transaction.IsIncome && transaction.Created.Month == month.Month
select transaction.Amount).DefaultIfEmpty().Sum(),
expense = (from account in household.Accounts
from transaction in account.Transactions
where !transaction.IsIncome && transaction.Created.Month == month.Month
select transaction.Amount).DefaultIfEmpty().Sum(),
};
我得到的是这个
.
.
.
[4] = { month = {5/1/2015 12:00:00 AM}, income = 3000, expense = 1804.75 }
[5] = { month = {6/1/2015 12:00:00 AM}, income = 2500, expense = 1560 }
[6] = { month = {7/1/2015 12:00:00 AM}, income = 0, expense = 550 }
.
.
.
因为flot需要一个数组,所以您可以在数组上运行一个循环,并汇总上个月的收入和支出。类似这样的内容(在现有代码之后):
您可以将此可重用扩展方法添加到代码中:
internal static class CollectionExtensions
{
/// <summary>
/// Returns a sequence whose first element is the first element of the source sequence (if any),
/// and every subsequent element is the result of applying a specified accumulator function to the
/// previous element of the resulting sequence and the next member of the source sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="accumulator"></param>
/// <returns></returns>
public static IEnumerable<T> Accumulate<T>(this IEnumerable<T> source, Func<T, T, T> accumulator)
{
if (source == null) throw new ArgumentNullException("source");
if (accumulator == null) throw new ArgumentNullException("accumulator");
return source.AccumulateImpl(accumulator);
}
private static IEnumerable<T> AccumulateImpl<T>(this IEnumerable<T> source, Func<T, T, T> accumulator)
{
using (var enumerator = source.GetEnumerator())
{
T accumulation;
T next;
if (enumerator.MoveNext())
accumulation = enumerator.Current;
else yield break;
yield return accumulation;
if (enumerator.MoveNext())
next = enumerator.Current;
else yield break;
while (true)
{
accumulation = accumulator(accumulation, next);
yield return accumulation;
if (enumerator.MoveNext())
next = enumerator.Current;
else yield break;
}
}
}
}
现在,如果您更改选择
以返回命名类型,而不是匿名类型(我假设您使用的是十进制
,如果不是,您可以调整此代码):
然后只需添加一行简单的代码:
var accumulated = sums.Accumulate((previous, next) => new MonthlyIncomeAndExpenses
{
Month = next.Month,
Income = previous.Income + next.Income,
Expense = previous.Expense + next.Expense,
});
是的,是的,我在捡你扔下来的东西。这很酷,不过thanksI发现聚合扩展有点像您所做的,但做得很好anyway@user4783644是的,
Aggregate
函数的作用基本相同,但我相信它只返回最终结果。因此,Accumulate().Last()
将等于Aggregate()
,这并非巧合。不同之处在于,这个函数在每一步都返回聚合,同时仍然只枚举原始序列一次(我假设这是您想要的)。
internal static class CollectionExtensions
{
/// <summary>
/// Returns a sequence whose first element is the first element of the source sequence (if any),
/// and every subsequent element is the result of applying a specified accumulator function to the
/// previous element of the resulting sequence and the next member of the source sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="accumulator"></param>
/// <returns></returns>
public static IEnumerable<T> Accumulate<T>(this IEnumerable<T> source, Func<T, T, T> accumulator)
{
if (source == null) throw new ArgumentNullException("source");
if (accumulator == null) throw new ArgumentNullException("accumulator");
return source.AccumulateImpl(accumulator);
}
private static IEnumerable<T> AccumulateImpl<T>(this IEnumerable<T> source, Func<T, T, T> accumulator)
{
using (var enumerator = source.GetEnumerator())
{
T accumulation;
T next;
if (enumerator.MoveNext())
accumulation = enumerator.Current;
else yield break;
yield return accumulation;
if (enumerator.MoveNext())
next = enumerator.Current;
else yield break;
while (true)
{
accumulation = accumulator(accumulation, next);
yield return accumulation;
if (enumerator.MoveNext())
next = enumerator.Current;
else yield break;
}
}
}
}
var range = Enumerable.Range(0, 5); // 0, 1, 2, 3, 4
var accumulated = range.Accumulate((x, y) => x + y); // 0, 1, 3, 6, 10
internal class MonthlyIncomeAndExpenses
{
public DateTime Month { get; set; }
public decimal Income { get; set; }
public decimal Expenses { get; set; }
}
var sums = from month in monthsToDate
select new MonthlyIncomeAndExpenses
{
Month = month,
Income = ..., // what you already have
Expense = ..., // what you already have
};
var accumulated = sums.Accumulate((previous, next) => new MonthlyIncomeAndExpenses
{
Month = next.Month,
Income = previous.Income + next.Income,
Expense = previous.Expense + next.Expense,
});