我正在尝试绘制一张邮票图表。我希望x轴从1月到12月为几个月,y轴为帐户余额。我有超过12个月的帐户收入和支出,但减去它们只会给我一个月的差额,它没有增加上个月的余额。
以下是我如何获得该范围内的收入和支出:
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 }
.
.
.
答案 0 :(得分:1)
由于你需要一个用于flot的数组数组,你可以在你的数组上运行一个循环,并总结上个月所有的收入和费用。这样的事情(在现有代码之后):
var flotDataAsList = new List<double[]>();
double balance = 0.0;
for (int i = 0; i <= 12; i++)
{
DateTime thisMonth = new DateTime(year, i, 1);
balance += sums.Where(m => m.month == thisMonth).Sum(m => m.income - m.expense);
flotDataAsList .Add(new double[] { GetJavascriptTimestamp(thisMonth), balance });
}
var flotDataAsArray = flotDataAsList.ToArray();
GetJavascriptTimestamp()
方法可以从flot documentation中获取:
public static int GetJavascriptTimestamp(System.DateTime input)
{
System.TimeSpan span = new System.TimeSpan(System.DateTime.Parse("1/1/1970").Ticks);
System.DateTime time = input.Subtract(span);
return (long)(time.Ticks / 10000);
}
答案 1 :(得分:1)
您可以将此可重复使用的扩展方法添加到您的代码中:
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
现在,如果您更改select
以返回命名类型,而不是匿名类型(我假设您正在使用decimal
获取资金 - 如果没有,则您可以改编这段代码):
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,
});