代码之家  ›  专栏  ›  技术社区  ›  alelom

条件依赖于其他序列元素的LINQ groupby

  •  0
  • alelom  · 技术社区  · 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
    

    我想分组 交易 在哪里 Debitor == Creditor ; 其他人在另一组。对于上一个示例,我应该得到:

      Group 1:
            luca       10          alessio 
            alessio    7           luca
            luca       1           alessio
      Group 2:
            giulia     12          alessio 
            alessio    6           giulia
      Group 3:
            marco      5           giulia
      Group 4:
            alessio    3           marco
    

    类似的问题可能是: LINQ Conditional Group

    2 回复  |  直到 6 年前
        1
  •  1
  •   Me.Name    6 年前

    最简单的方法就是创建一个组合键,比如在Anu的答案中。

    var groups = transactions.GroupBy(t=> t.Debitor.CompareTo(t.Creditor) > 0 ? (t.Debitor,t.Creditor) : (t.Creditor,t.Debitor));
    

    注意:以上假设您可以使用隐式元组创建。如果您有较低的C#版本和/或未安装ValueTuple NuGet软件包,则可以使用: var groups = transactions.GroupBy(t=> t.Debitor.CompareTo(t.Creditor) > 0 ? Tuple.Create(t.Debitor,t.Creditor) : Tuple.Create(t.Creditor,t.Debitor));


    纯粹为了说明这一点,另一种方法是为GROUPBY使用自定义相等比较器。根据您的需求、集合大小、对可重用性的需求等,这可能有些过分,但要显示出同样的可能性:首先创建一个类(或直接在事务中实现它)

    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();
    }
    

    然后,您可以使用

    var groups = transactions.GroupBy(t=>t, new TransactionDebCredComparer() );
    
        2
  •  1
  •   Anu Viswan    6 年前

    对于一个简单的解决方案,您可以使用由贷方和借方创建的密钥进行分组。例如

    string CreateKey(params string[] names)=>string.Join(",",names.OrderBy(x => x));
    var result = transactionCollection.GroupBy(x=> CreateKey(x.Debitor,x.Creditor)); 
    

    请注意,我在CreateKey中使用了一个集合,以防您有更多类似的分组因子,但是如果条件总是仅涉及债权人和借方,那么您可以为CreateKey编写一个更简单的版本。