【问题标题】:LINQ Composite Key GroupJoin with keys unknown at compile timeLINQ 复合键组在编译时使用未知键加入
【发布时间】:2013-07-12 14:52:21
【问题描述】:

我正在尝试让 GroupJoin 使用 LINQ 处理多个未知键。

我见过使用匿名类型的解决方案,但键始终是预定义的。 就我而言,它们是用户定义的,所以我在编译时不知道这些信息。我尝试使用键值列表和键值数组,但它们从不匹配。

所以...这就像一个魅力:

Func<Component, string> getKeyValue = x => x.Attributes                            //from attributes
                                            .Single(a => a.Name == _keyAttribute) //selects the key attribute
                                            .Value;                              //gets attribute value

var leftJoin = source.GroupJoin(target,                  //join
                                getKeyValue,            //on the same
                                getKeyValue,           //condition
                                (src, corresp) => new
                                {
                                   src,
                                   corresp
                                })
                    .SelectMany(z => z.corresp.DefaultIfEmpty()
                                              .Select(tgt => new { z.src, tgt })) //selects matching
                    .ToList();                                                   //source and target

但这不是:

Func<Component, List<string>> getKeyValues = x => x.Attributes                 //from attributes
                                 .Where(a => _keyAttributes.Contains(a.Name)) //selects key attributes
                                 .OrderBy(a => a.Name)                       //order them by name
                                 .Select(a => a.Value)                      //gets attributes' values
                                 .ToList();
var leftJoin = source.GroupJoin(target,                  //join
                                getKeyValues,           //on the same
                                getKeyValues,          //condition
                                (src, corresp) => new
                                {
                                   src,
                                   corresp
                                })
                    .SelectMany(z => z.corresp.DefaultIfEmpty()
                                              .Select(tgt => new { z.src, tgt })) //selects matching
                    .ToList();                                                   //source and target

如果有帮助,这就是我正在研究的结构:

List<string> _keyAttributes;
List<Component> source;
List<Component> target;

[DataContract]
public class Component
{
   [DataMember]
   public List<Attribute> Attributes { get; set; }

   public Component()
   {
      new List<Attribute>();
   }
}

[DataContract]
public class Attribute
{
    [DataMember]
    public string Name { get; set;}
    [DataMember]
    public string Value { get; set;}
}   

有没有办法使用 LINQ 库来解决这个问题,或者我需要自己的 GroupJoin 扩展方法来解决这个问题?

【问题讨论】:

    标签: c# linq join composite-key linq-group


    【解决方案1】:

    问题是您提供的 getKeyValues 选择器将从每个 Component 返回一个 List 以进行比较。每个返回的List 将通过reference 进行比较,所以基本上你已经完成了:

    var listA = new List<string> { "SomeString" };
    var listB = new List<string> { "SomeString" };
    
    bool areListsEqual = listA == listB;
    

    areListsEqual 将返回 false,因为它们是通过引用进行比较的。基本上您需要的是不同的EqualityComparer(可通过GroupJoin 的重载添加),或者您需要一种按比较属性的方法。

    一个可行的例子(但不一定是好方法)是:

    Func<Component, string> getKeyValues = x =>
        string.Join(",", x.Attributes
                          .Where(a => _keyAttributes.Contains(a.Name))
                          .OrderBy(a => a.Name)
                          .Select(a => a.Value).ToArray());
    

    这将创建一个字符串来表示每个列表中的值,并将用于比较。更好的方法是使用EqualityComparer,它具有您自己的逻辑,可以根据其中包含的值使列表实际上相等。请参阅 here 了解如何比较两个列表。

    【讨论】:

    • 没想过加入价值观。由于它们都是字符串,因此有效。我同意你的观点,这不一定是一个好方法,但我认为它会做。不是用逗号,而是用独特的字符组合。谢谢!
    • 想得更好,我将继续使用为 List 或 T[] 实现 EqualityComparer 并将其作为额外参数传递给 GroupJoin 的解决方案。
    • IEqualityComparer 是要走的路!谢谢!
    猜你喜欢
    • 2020-07-22
    • 1970-01-01
    • 1970-01-01
    • 2020-06-17
    • 1970-01-01
    • 2021-12-21
    • 1970-01-01
    • 2013-11-06
    • 1970-01-01
    相关资源
    最近更新 更多