Lamdba表达式可过滤相同编号的对

时间:2018-11-09 06:24:48

标签: c# linq lambda .net-core

我有一个表,用于记录项目的入库和出库。

 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

5 个答案:

答案 0 :(得分:0)

我想不出任何符合您要求的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 == "");

答案 1 :(得分:0)

尝试一下:

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

答案 2 :(得分:0)

我不确定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的对应项目的项目

答案 3 :(得分:0)

使用LINQ,您可以按Name分组,然后计算Status 0的数量,然后返回所有Status 1个跳过的{ Status排序的{1}} 0个对象。如果Created多于0,则不会为该1返回任何值。

Name

答案 4 :(得分:-1)

假设您只想删除名称出现为true和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);