C# 比较两个列表并使用linq返回不匹配的项
我有两张单子C# 比较两个列表并使用linq返回不匹配的项,c#,linq,list,c#-4.0,C#,Linq,List,C# 4.0,我有两张单子 List<Sent> SentList; List<Messages> MsgList; 我想将Msglist中的MsgID与sentlist进行比较,并需要使用linq将不在发送列表中的项目进行比较 Result MsgID Content 2 bbb 4 ddd 5 eee 天真的方法: MsgList.Where(x => !SentList.Any(y => y.MsgID == x.MsgID
List<Sent> SentList;
List<Messages> MsgList;
我想将Msglist中的MsgID与sentlist进行比较,并需要使用linq将不在发送列表中的项目进行比较
Result
MsgID Content
2 bbb
4 ddd
5 eee
天真的方法:
MsgList.Where(x => !SentList.Any(y => y.MsgID == x.MsgID))
请注意,这将需要多达
m*n
操作,因为它会将SentList
中的每个MsgID
与MsgList
中的每个MsgID>进行比较(“最多”,因为它在匹配时会短路)。您可以执行以下操作:
HashSet<int> sentIDs = new HashSet<int>(SentList.Select(s => s.MsgID));
var results = MsgList.Where(m => !sentIDs.Contains(m.MsgID));
HashSet sentIDs=newhashset(SentList.Select(s=>s.MsgID));
var results=MsgList.Where(m=>!sentIDs.Contains(m.MsgID));
这将返回MsgList
中所有在SentList
中没有匹配ID的消息。您可以执行以下操作
var notSent = MsgSent.Except(MsgList, MsgIdEqualityComparer);
您将需要提供MSDN上概述的自定义相等比较器
只需让相等比较器仅在每个相应类型的MsgID属性上建立相等。由于相等比较器比较同一类型的两个实例,因此您需要定义一个接口或公共基类型,该接口或公共基类型由发送和消息实现,并具有MsgID属性。List cars=new List(){new Car(){Name=“Ford”,Year=1892,Website=“www.Ford.us”},
新车(){Name=“Jaguar”,年份=1892,网址=“www.Jaguar.co.uk”},
新车(){Name=“Honda”,Year=1892,网址=“www.Honda.jp”};
List factories=new List(){new Factory(){Name=“Ferrari”,Website=“www.Ferrari.it”},
新工厂(){Name=“Jaguar”,网站=“www.Jaguar.co.uk”},
新工厂(){Name=“BMW”,网址=“www.BMW.de”};
foreach(cars-Car-in-cars.Where(c=>!factories.Any)(f=>f.Name==c.Name))){
lblDebug.Text+=car.Name;
}
好吧,你已经有了很好的答案,但它们都是很好的答案。更为LINQ的方法如下
var NotSentMessages =
from msg in MsgList
where !SentList.Any(x => x.MsgID == msg.MsgID)
select msg;
试试看
已发送公共类
{
公共int MsgID;
公共字符串内容;
公众地位;
}
公共类消息
{
公共int MsgID;
公共字符串内容;
}
List SentList=new List(){new Sent(){MsgID=1,Content=“aaa”,Status=0},new Sent(){MsgID=3,Content=“ccc”,Status=0};
List MsgList=new List(){new Messages(){MsgID=1,Content=“aaa”},new Messages(){MsgID=2,Content=“bbb”},new Messages(){MsgID=3,Content=“ccc”},new Messages(){MsgID=4,Content=“ddd”},new Messages(){MsgID=5,Content=“eee”};
int[]sentMsgIDs=SentList.Select(v=>v.MsgID.ToArray();
List result1=MsgList.Where(o=>!sentMsgIDs.Contains(o.MsgID)).ToList();
希望能有所帮助。你可以这样做,这是最快的过程
Var result = MsgList.Except(MsgList.Where(o => SentList.Select(s => s.MsgID).ToList().Contains(o.MsgID))).ToList();
这将为您提供预期的输出。作为扩展方法
public static IEnumerable<TSource> AreNotEqual<TSource, TKey, TTarget>(this IEnumerable<TSource> source, Func<TSource, TKey> sourceKeySelector, IEnumerable<TTarget> target, Func<TTarget, TKey> targetKeySelector)
{
var targetValues = new HashSet<TKey>(target.Select(targetKeySelector));
return source.Where(sourceValue => targetValues.Contains(sourceKeySelector(sourceValue)) == false);
}
公共静态IEnumerable AreNotEqual(此IEnumerable源、Func sourceKeySelector、IEnumerable目标、Func targetKeySelector)
{
var targetValues=newhashset(target.Select(targetKeySelector));
返回source.Where(sourceValue=>targetValues.Contains(sourceKeySelector(sourceValue))==false);
}
例如
公共类客户
{
public int CustomerId{get;set;}
}
公共类客户
{
公共int Id{get;set;}
}
var customers=新列表()
{
新客户(){CustomerId=1},
新客户(){CustomerId=2}
};
var others=新列表()
{
新建OtherCustomer(){Id=2},
新建OtherCustomer(){Id=3}
};
var result=customers.AreNotEqual(customer=>customer.CustomerId,others,other=>other.Id).ToList();
Assert(result.Count==1);
Assert(结果[0]。CustomerId==1);
如果要从第二个列表中选择列表中的项目:
MainList.Where(p=>2ndlist.Contains(MainList中的p.columns)).ToList() 这可能是最好的方法如果你需要比较多个属性呢?(例如Id和版本号?@NickG,然后你为它创建一个类,实现IEqualityComparer,并生成一个哈希集
。啊,与lc.posted完全相同的解决方案。但是,好吧,这里有一个完整且经过测试的示例。如果你要投反对票,你至少可以礼貌地向我解释一下原因。怎么样:MsgList.Where(x=>SentList.All(y=>y.MsgID==x.MsgID))
@zumalifeguard我想你的意思是!=
,如果是的话,它是一个逻辑上等价的表达式,应该花费相同的时间。别忘了将帮助你解决问题的答案标记为正确=)var NotSentMessages=来自MsgList中的msg where!任何(x=>x.MsgID==msg.MsgID&&x.content==msg.content)选择msg
这更适合于比较多个属性(组合键)@AndrewDay是的,但是OP说他想检查相等的ID,所以这里没有必要匹配字符串。-所以你的代码更好,因为它是可扩展的。但这是一个糟糕的评论???@AndrewDay一点也不,伙计,我只是解释为什么我只匹配ID.:)@AndreCalil:LINQ支持两种语法。。。“查询语法和方法语法在语义上是相同的…”从中可以为选择器使用多个属性吗?@Rebecca我认为这会起作用:)var result=customers.AreNotEqual(customer=>(customer.CustomerId,customer.CustomerName),other,other=>(other.Id,other.Name)).ToList();
public class Sent
{
public int MsgID;
public string Content;
public int Status;
}
public class Messages
{
public int MsgID;
public string Content;
}
List<Sent> SentList = new List<Sent>() { new Sent() { MsgID = 1, Content = "aaa", Status = 0 }, new Sent() { MsgID = 3, Content = "ccc", Status = 0 } };
List<Messages> MsgList = new List<Messages>() { new Messages() { MsgID = 1, Content = "aaa" }, new Messages() { MsgID = 2, Content = "bbb" }, new Messages() { MsgID = 3, Content = "ccc" }, new Messages() { MsgID = 4, Content = "ddd" }, new Messages() { MsgID = 5, Content = "eee" }};
int [] sentMsgIDs = SentList.Select(v => v.MsgID).ToArray();
List<Messages> result1 = MsgList.Where(o => !sentMsgIDs.Contains(o.MsgID)).ToList<Messages>();
Var result = MsgList.Except(MsgList.Where(o => SentList.Select(s => s.MsgID).ToList().Contains(o.MsgID))).ToList();
public static IEnumerable<TSource> AreNotEqual<TSource, TKey, TTarget>(this IEnumerable<TSource> source, Func<TSource, TKey> sourceKeySelector, IEnumerable<TTarget> target, Func<TTarget, TKey> targetKeySelector)
{
var targetValues = new HashSet<TKey>(target.Select(targetKeySelector));
return source.Where(sourceValue => targetValues.Contains(sourceKeySelector(sourceValue)) == false);
}
public class Customer
{
public int CustomerId { get; set; }
}
public class OtherCustomer
{
public int Id { get; set; }
}
var customers = new List<Customer>()
{
new Customer() { CustomerId = 1 },
new Customer() { CustomerId = 2 }
};
var others = new List<OtherCustomer>()
{
new OtherCustomer() { Id = 2 },
new OtherCustomer() { Id = 3 }
};
var result = customers.AreNotEqual(customer => customer.CustomerId, others, other => other.Id).ToList();
Debug.Assert(result.Count == 1);
Debug.Assert(result[0].CustomerId == 1);
List<Person> persons1 = new List<Person>
{
new Person {Id = 1, Name = "Person 1"},
new Person {Id = 2, Name = "Person 2"},
new Person {Id = 3, Name = "Person 3"},
new Person {Id = 4, Name = "Person 4"}
};
List<Person> persons2 = new List<Person>
{
new Person {Id = 1, Name = "Person 1"},
new Person {Id = 2, Name = "Person 2"},
new Person {Id = 3, Name = "Person 3"},
new Person {Id = 4, Name = "Person 4"},
new Person {Id = 5, Name = "Person 5"},
new Person {Id = 6, Name = "Person 6"},
new Person {Id = 7, Name = "Person 7"}
};
var output = (from ps1 in persons1
from ps2 in persons2
where ps1.Id == ps2.Id
select ps2.Name).ToList();
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}