【问题标题】:Lambda Expression to filter pair of same number用于过滤相同数字对的 Lambda 表达式
【发布时间】:2019-04-12 17:35:18
【问题描述】:

我有一个记录进出项目的表格。

 Id    Name Status Created
 1     A1   1      9/11/2018 14:00:00 <- 1
 2     A1   1      9/11/2018 14:01:00 <- 2
 3     A1   1      9/11/2018 14:02:00 <- 3
 4     A2   1      9/11/2018 14:03:00 <- 4
 5     A3   1      9/11/2018 14:04:00 <- 5
 6     A1   0      9/11/2018 14:05:00 <- consider 1 is taken out.
 7     A1   1      9/11/2018 14:06:00 <- 6

我想过滤这对;索引 1 和索引 6,来自表。并将状态为 1 的项目留给我。正确的表格应如下所示

 Id    Name Status Created

 2     A1   1      9/11/2018 14:01:00 <- 2
 3     A1   1      9/11/2018 14:02:00 <- 3
 4     A2   1      9/11/2018 14:03:00 <- 4
 5     A3   1      9/11/2018 14:04:00 <- 5

 7     A1   1      9/11/2018 14:06:00 <- 6

但我的 lambda 表达式用于过滤状态为 1 的项目

public class Item {
   public int Id;
   public string Name;
   public bool Status;
   public DateTime;
}
var Items = new List<Item>();
// This give me everything
Items = await db.items.Where(i => i.Status == true).ToListAsync();

我得到了每个状态为 1 的项目的列表

 Id    Name Status Created
 1     A1   1      9/11/2018 14:00:00 <- 1
 2     A1   1      9/11/2018 14:01:00 <- 2
 3     A1   1      9/11/2018 14:02:00 <- 3
 4     A2   1      9/11/2018 14:03:00 <- 4
 5     A3   1      9/11/2018 14:04:00 <- 5

 7     A1   1      9/11/2018 14:06:00 <- 6

如何应用 lambda 表达式过滤出要从列表中删除的同名对?我想知道任何带有 lambda 表达式的快捷方式来过滤此类列表?

例子:

 Id  Name Status DateTime             Id Name Status DateTime
  6  A1   0      9/11/2018 14:05:00   1  A1   1      9/11/2018 14:00:00
  // this id 1 and id 6 i want to remove based on name and date time
                                      2  A1   1      9/11/2018 14:01:00
                                      3  A1   1      9/11/2018 14:02:00 
                                      4  A2   1      9/11/2018 14:03:00
                                      5  A3   1      9/11/2018 14:04:00
                                      7  A1   1      9/11/2018 14:06:00

【问题讨论】:

  • OrderBy 创建降序。然后使用按名称分组,然后获取第一个结果。 var results = db.items.OrderByDescending(x => x.Created).Group(x => x.Name).Select(x => x.FirstOrDefault()).ToList();
  • 你能解释一下为什么只过滤掉 ID 1 吗?它不是最接近日期的“对”。或者您的意思是如果多个条目具有相同的名称,您要过滤最早的条目?
  • @Sweeper,我想先删除日期时间最早的一对。
  • 这个逻辑可以用lambda表达式吗?
  • 我对你在做什么感到很困惑。你能解释一下为什么要删除 ID 1 和 6 吗? ID 6 没有名称为 A1 的所有条目中的最早日期。 ID 1 和 2 不应该去掉吗?

标签: c# linq lambda .net-core


【解决方案1】:

试试这个:

// your original data
var Items = new List<Item>();

// those items with status 0
var itemsToBeRemoved = Items.Where(x => !x.Status);

// remove those first
Items.RemoveAll(itemsToBeRemoved.Contains);

// now find the things with the same name, order by date, get the first one.
var theOtherItemsToBeRemoved = itemsToBeRemoved.Select(x => 
    Items.Where(y => y.Name == x.Name).OrderBy(y => y.Created).FirstOrDefault()
).ToList();

// now remove the items found
Items.RemoveAll(theOtherItemsToBeRemoved.Contains);

【讨论】:

  • 我比其他人更喜欢这个答案,因为它简单且易于添加。我测试了另一个答案,让我在第一次尝试 esp 设置查找表时有点困惑。
【解决方案2】:

我想不出任何符合您要求的 LINQ 扩展方法,但您可以通过嵌套循环轻松实现它,如下所示:

  // Data generation
  var items = new List<Item>();
  for (int i = 0; i < 7; i++)
    items.Add(new Item() { Id = i + 1, Dt = DateTime.Parse("9/11/2018 14:00:00").AddMinutes(i), Name = "A1", Status = true });
  items[3].Name = "A2";
  items[4].Name = "A3";
  items[5].Status = false;

  // It's also good to make sure that elements are in correct order
  items = items.OrderBy(i => i.Dt).ToList();

  // Procedure, to execute your logic
  for (int i = 0; i < items.Count(); i++)
  {
    // If it has Status = true, then look for "enclosing" element with Status = false
    if(items[i].Status)
      for (int j = i + 1; j < items.Count(); j++)
      {
        if(!items[j].Status && items[j].Name == items[i].Name)
        {
          // Mark items, so we delete them (and recognize those with status 0 as used)
          items[i].Name = "";
          items[j].Name = "";
        }
      }
  }
  // Remove all marked elements
  items.RemoveAll(i => i.Name == "");

【讨论】:

    【解决方案3】:

    我不确定 LINQ-to-Entity 表达式,但在内存中加载项目后,您可以删除在数据库中“标记”为已删除的项目。

    var items = await db.items.OrderBy(item => item.Created).ToListAsync();
    
    var stillInItems = items.GroupBy(item => item.Name)
                            .Select(group => group.ToLookup(item => item.Status))
                            .SelectMany(lookup => 
                            {
                                var outItemsCount = lookup[false].Count();
                                return lookup[true].Skip(outItemsCount);
                            })
                            .ToList();
    

    我认为也可以在 SQL 中执行 - 使用 ROW_NUMBER 处理具有相同名称和状态的项目,然后排除具有相同 ROW_NUMBER 但状态 = 0 的对应项目的项目。

    【讨论】:

      【解决方案4】:

      使用 LINQ,您可以按Name 分组,然后统计Status 0 的数量,然后返回所有Status 1 的跳过计数Status 0 按@987654328 排序的对象@。如果0 多于1,则不会为该Name 返回任何内容。

      var filtered = src
                      .GroupBy(s => s.Name)
                      .SelectMany(g => { // for each name group
                          var skipCount = g.Where(r => r.Status == 0).Count(); // count the 0 status
                          return g.Where(r => r.Status == 1).OrderBy(r => r.Created).Skip(skipCount); // return the 1 status without earliest matched to 0 status
                      })
                      .OrderBy(s => s.Id);
      

      【讨论】:

        【解决方案5】:

        假设您只想删除每个名称的第一次出现的 Status true 和 Status false 我想这是可行的:

        // Create lookup
        ILookup<string, Item> lookupItems = Items.OrderBy(ordBy => ordBy.Created)
                                                 .ToLookup(l => l.Name);
        
        // Iterate through your collection
        Items.RemoveAll(item => lookupItems[item.Name].Any(lookupItem => !lookupItem.Status)
             ? lookupItems[item.Name].First(lookupItem => !lookupItem.Status).Id == item.Id || 
               lookupItems[item.Name].First(lookupItem => lookupItem.Status).Id == item.Id
             : false);
        

        【讨论】:

        • 当集合有多个相同名称的状态 = 0 的项目时,这将不起作用。
        • 它只会删除第一个状态 1 和第一个状态 0 确实,该名称的其他条目保持不变
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多