我有两个Lists
。我想根据 ID 获取匹配和不匹配的值,并将结果添加到另一个List
。我可以使用Intersect/Except
获得这两个。
但我只能在结果变量(匹配和不匹配)中获得 ID 。我需要模板中的所有属性。
List<Template> listForTemplate = new List<Template>();
List<Template1> listForTemplate1 = new List<Template1>();
var matches = listForTemplate .Select(f => f.ID)
.Intersect(listForTemplate1 .Select(b => b.ID));
var ummatches = listForTemplate .Select(f => f.ID)
.Except(listForTemplate1.Select(b => b.ID));
public class Template
{
public string ID{ get; set; }
public string Name{ get; set; }
public string Age{ get; set; }
public string Place{ get; set; }
public string City{ get; set; }
public string State{ get; set; }
public string Country{ get; set; }
}
public class Template1
{
public string ID{ get; set; }
}
答案 0 :(得分:3)
如果您不想为此简单任务实现IEquality
,则只需修改LINQ查询:
var matches = listForTemplate.Where(f => listForTemplate1.Any(b => b.ID == f.ID));
和
var unmatches = listForTemplate.Where(f => listForTemplate1.All(b => b.ID != f.ID));
您可能希望在访问ID
之前检查null,但它应该有效。
答案 1 :(得分:2)
您正在寻找重载函数,第二个参数是IEqualityComparer。所以制作你的比较器(例如:http://www.blackwasp.co.uk/IEqualityComparer.aspx),并在intersect / except中使用相同的比较器。
对于通用部分:也许你应该有一个模板的通用接口,例如ObjectWithID描述该类具有字符串ID属性。或者只是在比较器中使用dynamic(但我认为这是非常非常反模式的,因为如果使用错误类型,可能会出现运行时错误。)
您还有一个问题:两个不同类型的集合相交会产生一个Object(公共父类)的集合。然后你必须投了很多(反模式)。我建议你为你的模板类创建一个通用的抽象类/接口,它正在工作。如果你需要将元素强制转换,请不要强制转换,而是使用visitior模式:http://en.wikipedia.org/wiki/Visitor_pattern
示例(好):
static void Main(string[] args)
{
// http://stackoverflow.com/questions/16496998/how-to-copy-a-list-to-another-list-with-comparsion-in-c-sharp
List<Template> listForTemplate = new Template[] {
new Template(){ID = "1"},
new Template(){ID = "2"},
new Template(){ID = "3"},
new Template(){ID = "4"},
new Template(){ID = "5"},
new Template(){ID = "6"},
}.ToList();
List<Template1> listForTemplate1 = new Template1[] {
new Template1(){ID = "1"},
new Template1(){ID = "3"},
new Template1(){ID = "5"}
}.ToList();
var comp = new ObjectWithIDComparer();
var matches = listForTemplate.Intersect(listForTemplate1, comp);
var ummatches = listForTemplate.Except(listForTemplate1, comp);
Console.WriteLine("Matches:");
foreach (var item in matches) // note that item is instance of ObjectWithID
{
Console.WriteLine("{0}", item.ID);
}
Console.WriteLine();
Console.WriteLine("Ummatches:");
foreach (var item in ummatches) // note that item is instance of ObjectWithID
{
Console.WriteLine("{0}", item.ID);
}
Console.WriteLine();
}
}
public class ObjectWithIDComparer : IEqualityComparer<ObjectWithID>
{
public bool Equals(ObjectWithID x, ObjectWithID y)
{
return x.ID == y.ID;
}
public int GetHashCode(ObjectWithID obj)
{
return obj.ID.GetHashCode();
}
}
public interface ObjectWithID {
string ID { get; set; }
}
public class Template : ObjectWithID
{
public string ID { get; set; }
public string Name { get; set; }
public string Age { get; set; }
public string Place { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
}
public class Template1 : ObjectWithID
{
public string ID { get; set; }
}
输出:
Matches:
1
3
5
Ummatches:
2
4
6
Press any key to continue . . .
答案 2 :(得分:1)
为了比较,这也应该有效(第一部分是@ MAV答案的变体):
var matches = from item in listForTemplate
join id in listForTemplate1 on item.ID equals id.ID
select item;
var unmatches = listForTemplate.Where(item => matches.All(elem => elem.ID != item.ID));
matches
和unmatches
都是IEnumerable<Template>
,这是您需要的类型。
但是,MAV的答案很好,所以我会选择那个。
答案 3 :(得分:0)
如上所述,实施IEqualityComparer<T>
界面。
然后在Except()
和Intersect()
有一个很好的示例,说明如何在Intersect()
方法的链接上执行此操作。
答案 4 :(得分:0)
如果您不必使用LINQ,为什么不编写类似这样的代码?
var matches = new List<Template>();
var unmatches = new List<Template>();
foreach (var entry in listForTemplate)
{
bool matched = false;
foreach (var t1Entry in listForTemplate1)
{
if (entry.ID == t1Entry.ID)
{
matches.Add(entry);
matched = true;
break;
}
}
if (!matched)
{
unmatches.Add(entry);
}
}
LINQ方法的一个缺点是你要遍历列表两次。