EDITコードの 2 番目のブロックの説明と太字の重要な免責事項については、最後に移動してください。
var query = from acct in accts
select new
{
acct.From,
acct.To,
acct.Amount,
FirstOrientedAmount = ((acct.From.CompareTo(acct.To) == -1 && acct.Amount < 0) ||
(acct.From.CompareTo(acct.To) >= 0 && acct.Amount > 0)) ? acct.Amount : 0,
SecondOrientedAmount = ((acct.From.CompareTo(acct.To) >= 0 && acct.Amount < 0) ||
(acct.From.CompareTo(acct.To) == -1 && acct.Amount > 0)) ? acct.Amount * -1 : 0
} into r
group r by new
{
First = (r.From.CompareTo(r.To) == -1 ? r.From : r.To),
Second = (r.From.CompareTo(r.To) == -1 ? r.To : r.From)
} into g
select new
{
First = g.Sum(acctval => acctval.FirstOrientedAmount) + g.Sum(acctval => acctval.SecondOrientedAmount) > 0 ? g.Key.Second : g.Key.First,
Second = g.Sum(acctval => acctval.FirstOrientedAmount) + g.Sum(acctval => acctval.SecondOrientedAmount) > 0 ? g.Key.First : g.Key.Second,
FTotal = g.Sum(acctval => acctval.FirstOrientedAmount),
STotal = g.Sum(acctval => acctval.SecondOrientedAmount),
Total = g.Sum(acctval => acctval.FirstOrientedAmount) + g.Sum(acctval => acctval.SecondOrientedAmount),
};
これは与える:
CAD USD -150
GBP AUD 500
編集:これらの要件を完全には理解していないため、古いコードを残していますが、最適化するためにコンパイラに依存しないものを投稿しています:
var query = from p in accts
select new
{
p.From,
p.To,
p.Amount,
OrientedAmount = ((p.From.CompareTo(p.To) == -1 && p.Amount < 0) ||
(p.From.CompareTo(p.To) >= 0 && p.Amount > 0)) ? p.Amount : p.Amount * -1
} into r
group r by new
{
First = (r.From.CompareTo(r.To) == -1 ? r.From : r.To),
Second = (r.From.CompareTo(r.To) == -1 ? r.To : r.From)
} into g
select new
{
g.Key.First,
g.Key.Second,
Total = g.Sum(val => val.OrientedAmount)
} into last
select new
{
First = last.Total > 0 ? last.Second : last.First,
Second = last.Total > 0 ? last.First : last.Second,
Total = last.Total
};
これは、最初にすべての金額を From アカウントが辞書式に並べられた最大の通貨名であるトランザクションに向けることによって機能します。現在のトランザクション ラインが辞書順で最小の通貨名に向かって資金を移動している場合は、金額の符号を反転させます。
次に、トランザクション内のアカウントを辞書順に並べてグループ化します。
合計を選択します (これを行う必要があるのは 1 回だけです)。これを行うには、すべての指向量を追加します。
合計値が正の場合 (私が行った方法)、辞書式に並べられた最大の通貨名に正味の値が入ります。負の場合、正味の値は辞書式に並べられた最小の通貨名になります。
ただし、これらが適切な要件であるとは確信していません (または、元の要件を誤解しています)。この問題が何を解決しているのかを見ると、「AB売り」「AB買い」「BA買い」「BA売り」を1つのグループにまとめています。この場合、「AB 100」は「AB -100」を意味します。1 つ目は 100 A を購入することを意味し、2 つ目は 100 B を A に売却することを意味します。この問題の解決方法を見ると、 それらは同じことです。 しかし実際には、 それらは同じものではありません。 100 B を売っても、100 A を買ったのと同じ量の A は得られません。これを正規化するには、為替レートが必要です。