LINQ。我有一个a
Out[191]: array([4, 5, 3])
b
Out[192]: array([1, 2, 6])
类型的IEnumerable:
Transaction
示例private class Transaction{
public string Debitor { get; set; }
public double Debit { get; set; }
public string Creditor { get; set; } }
:
IEnumerable<Transaction>
我想将[Debitor] | [Spend] | [Creditor]
luca 10 alessio
giulia 12 alessio
alessio 7 luca
alessio 6 giulia
marco 5 giulia
alessio 3 marco
luca 1 alessio
== Transaction
的{{1}}分组;其他在单独的组中。对于前面的示例,我应该得到:
Debitor
我已经在同一个IEnumerable上使用2个for循环(一个嵌套)解决了该问题,执行了检查并为输出使用了单独的列表,但是我想知道是否有使用LINQ进行此操作的笨拙方法。
类似的问题可能是:LINQ Conditional Group,但是在这种情况下,分组条件取决于IEnumerable的其他元素。
答案 0 :(得分:1)
对于一个简单的解决方案,您可以使用由Creditor和Debitor创建的密钥进行分组。例如。
string CreateKey(params string[] names)=>string.Join(",",names.OrderBy(x => x));
var result = transactionCollection.GroupBy(x=> CreateKey(x.Debitor,x.Creditor));
请注意,如果您有更多相似的分组因子,我会在CreateKey中使用一个集合,但是如果条件始终始终只涉及债权人和借方,则可以为CreateKey写一个更简单的版本。
答案 1 :(得分:1)
最简单的方法确实是创建一个组合键,例如在Anu的答案中。 另一种方法(不一定更好,但避免了子集合和字符串连接)是:
argparse
NB以上假设您可以使用隐式元组创建。如果您使用较低的C#版本和/或未安装ValueTuple NuGet软件包,则可以使用:var groups = transactions.GroupBy(t=> t.Debitor.CompareTo(t.Creditor) > 0 ? (t.Debitor,t.Creditor) : (t.Creditor,t.Debitor));
为方便起见,另一种方式是对group by使用自定义的相等比较器。根据您的需要,集合大小,可重用性等因素,这可能是过大的,但是为了展示出相同的可能性:首先创建一个类(或直接在Transaction中实现)
var groups = transactions.GroupBy(t=> t.Debitor.CompareTo(t.Creditor) > 0 ? Tuple.Create(t.Debitor,t.Creditor) : Tuple.Create(t.Creditor,t.Debitor));
然后您可以使用来对可枚举分组
class TransactionDebCredComparer : EqualityComparer<Transaction>
{
public override bool Equals(Transaction t1, Transaction t2) => (t1.Debitor == t2.Creditor && t2.Debitor == t1.Creditor) || (t1.Debitor == t2.Debitor && t2.Creditor == t1.Creditor);
public override int GetHashCode(Transaction t) => t.Debitor.GetHashCode() ^ t.Creditor.GetHashCode();
}