【问题标题】:compare two list and return not matching items using linq比较两个列表并使用 linq 返回不匹配的项目
【发布时间】:2012-08-14 17:33:14
【问题描述】:

我有两个列表

List<Sent> SentList;
List<Messages> MsgList;

两者都具有称为 MsgID 的相同属性;

MsgList            SentList  

MsgID Content      MsgID Content Stauts
1       aaa        1       aaa     0
2       bbb        3       ccc     0
3       ccc        
4       ddd
5       eee

我想将 Msglist 中的 MsgID 与 sentlist 进行比较,并需要使用 linq 不在已发送列表中的项目

Result 

MsgID Content
2       bbb
4       ddd
5       eee

【问题讨论】:

  • 别忘了将帮助您解决问题的答案标记为正确 =)

标签: c# linq list c#-4.0


【解决方案1】:

你可以这样做:

HashSet<int> sentIDs = new HashSet<int>(SentList.Select(s => s.MsgID));

var results = MsgList.Where(m => !sentIDs.Contains(m.MsgID));

这将返回MsgList 中没有SentList 中匹配ID 的所有消息。

【讨论】:

  • 这可能是最好的方法
  • 如果您需要比较多个属性怎么办? (例如 ID 和版本号?
  • @NickG 然后为它创建一个实现 IEqualityComparer 的类,并改为创建一个HashSet&lt;className&gt;
【解决方案2】:

天真的方法:

MsgList.Where(x => !SentList.Any(y => y.MsgID == x.MsgID))

请注意,这将需要最多 m*n 操作,因为它将 SentList 中的每个 MsgIDMsgList 中的每个 MsgList 进行比较(“最多”,因为它会在它发生时短路 em> 恰好匹配)。

【讨论】:

  • 如果你要投反对票,你至少可以向我解释原因。
  • 怎么样:MsgList.Where(x =&gt; SentList.All(y =&gt; y.MsgID == x.MsgID))
  • @zumalifeguard 我想你的意思是!=,如果是的话,它是一个逻辑上等价的表达式,应该花费相同的时间。
【解决方案3】:

嗯,你已经有了很好的答案,但它们大多是 Lambda。更多的 LINQ 方法就像

var NotSentMessages =
                from msg in MsgList
                where !SentList.Any(x => x.MsgID == msg.MsgID)
                select msg;

【讨论】:

  • var NotSentMessages = from msg in MsgList where !SentList.Any(x =&gt; x.MsgID == msg.MsgID &amp;&amp; x.content == msg.content) select msg; 这更适合比较多个属性(组合键)
  • @AndrewDay 是的,但 OP 说他想检查相等的 ID,所以这里不需要匹配字符串。
  • - 所以你的代码是更好的代码,因为它是可扩展的。但这是一个不好的评论????
  • @AndrewDay 根本不是人,我只是在解释为什么我只匹配 ID。 :)
  • @AndreCalil Calil:LINQ 支持两种语法...“查询语法和方法语法在语义上是相同的...”来自docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…
【解决方案4】:

你可以这样做,这是最快的过程

Var result = MsgList.Except(MsgList.Where(o => SentList.Select(s => s.MsgID).ToList().Contains(o.MsgID))).ToList();

这将为您提供预期的输出。

【讨论】:

  • 我很确定您会在 Where 函数的每次迭代中从 SentList 中创建一个列表。没有办法有效。首先将 SentList.Select(s =&gt; s.MsgID).ToList() 存储在 where 语句之外的变量中。
【解决方案5】:

你可以这样做

var notSent = MsgSent.Except(MsgList, MsgIdEqualityComparer);

您需要提供 MSDN 上概述的自定义相等比较器

http://msdn.microsoft.com/en-us/library/bb336390.aspx

只需让相等比较器基于每个相应类型的 MsgID 属性的相等性。由于相等比较器比较相同类型的两个实例,因此您需要定义 SentMessages 都实现的具有 MsgID 的接口或公共基类型 属性。

【讨论】:

    【解决方案6】:

    试试,

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

    希望它会有所帮助。

    【讨论】:

      【解决方案7】:

      作为扩展方法

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

      【讨论】:

      • 是否可以为选择器使用多个属性?
      • @Rebecca 我认为这可行:) var result = customers .AreNotEqual(customer => (customer.CustomerId, customer.CustomerName), others, other => (other.Id, other.Name )) .ToList();
      【解决方案8】:
      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; }
      }
      

      【讨论】:

        【解决方案9】:

        如果你想从第二个列表中选择列表项:

        MainList.Where(p => 2ndlist.Contains(p.columns from MainList )).ToList();

        【讨论】:

          【解决方案10】:
          List<Car> cars = new List<Car>() {  new Car() { Name = "Ford", Year = 1892, Website = "www.ford.us" }, 
                                              new Car() { Name = "Jaguar", Year = 1892, Website = "www.jaguar.co.uk" }, 
                                              new Car() { Name = "Honda", Year = 1892, Website = "www.honda.jp"} };
          
          List<Factory> factories = new List<Factory>() {     new Factory() { Name = "Ferrari", Website = "www.ferrari.it" }, 
                                                              new Factory() { Name = "Jaguar", Website = "www.jaguar.co.uk" }, 
                                                              new Factory() { Name = "BMW", Website = "www.bmw.de"} };
          
          foreach (Car car in cars.Where(c => !factories.Any(f => f.Name == c.Name))) {
              lblDebug.Text += car.Name;
          }
          

          【讨论】:

          • 啊,和lc完全一样的解决方案。张贴。但是,这里有一个完整且经过测试的示例。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-12-23
          • 2020-12-19
          • 1970-01-01
          • 1970-01-01
          • 2010-11-26
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多