我正在尝试让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扩展方法来做到这一点?
答案 0 :(得分:0)
问题是您提供的getKeyValues选择器会从每个List
返回Component
以进行比较。每个返回的List
将通过引用进行比较,所以基本上你已经开始了:
var listA = new List<string> { "SomeString" };
var listB = new List<string> { "SomeString" };
bool areListsEqual = listA == listB;
areListsEqual
将返回false,因为它们是通过引用进行比较的。基本上你需要的是一个不同的EqualityComparer
(可以通过GroupJoin
的重载添加),或者你需要一种方法来通过 value 来比较属性。 / p>
可行的一些例子(但不一定是一种好方法)将是:
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。