Выражение Lamdba для фильтрации пары с одинаковым номером - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть таблица, в которой записываются входящие и исходящие данные.

 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

но мое лямбда-выражение фильтрует элементы со статусом 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

Как мне применить лямбда-выражение, чтобы отфильтровать пару с тем же именем, чтобы удалить из моего списка? Я хочу знать любой ярлык с лямбда-выражением для фильтрации такого списка?

Примеры:

 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 голосов
/ 09 ноября 2018

Используя LINQ, вы можете сгруппировать по Name, затем посчитать число Status 0 и затем вернуть все Status 1 количество пропусков Status 0 объектов, упорядоченных по Created. Если их больше 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);
0 голосов
/ 09 ноября 2018

Я не уверен насчет выражения 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.

0 голосов
/ 09 ноября 2018

Попробуйте это:

// 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);
0 голосов
/ 09 ноября 2018

Предполагая, что вы хотите удалить только первые вхождения как с 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 голосов
/ 09 ноября 2018

Я не могу придумать какой-либо метод расширения 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 == "");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...