1

I have following classes

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int CategoryId { get; set; }
    public int SectionId { get; set; }
    public string VendorName { get; set; }
}

public class ProductToRemove
{
    public int CategoryId { get; set; }
    public int SectionId { get; set; }
}

In the main I have list of these two classes as follows.

List<Product> Products = new List<Product>()
{
    new Product() { Id = 1, Name = "A", CategoryId = 11, SectionId = 6, VendorName = "ABC" },
    new Product() { Id = 2, Name = "B", CategoryId = 21, SectionId = 6, VendorName = "ABC" },
    new Product() { Id = 3, Name = "C", CategoryId = 13, SectionId = 8, VendorName = "ABC" },
    new Product() { Id = 4, Name = "D", CategoryId = 90, SectionId = 6, VendorName = "ABC" },
    new Product() { Id = 5, Name = "E", CategoryId = 25, SectionId = 9, VendorName = "ABC" },
};

    List<ProductToRemove> ProductsToRemove = new List<ProductToRemove>()
    {
        new ProductToRemove() {CategoryId = 11, SectionId = 6,  },
        new ProductToRemove() {CategoryId = 90, SectionId = 6,  }
    };

I want to remove anything from Products instance where CategoryId and SectionId matches what is in the ProductsToRemove collection. I know how to loop through Products collection and delete matching records but I am wondering if there is a way to do the same using Linq

jim crown
  • 473
  • 3
  • 11
  • Possible duplicate of [Remove item from list based on condition](http://stackoverflow.com/questions/3279145/remove-item-from-list-based-on-condition) – pookie Jan 25 '17 at 20:19
  • 3
    LINQ would also use a loop -- it isn't magic. In fact, using LINQ here (with `GroupBy`/`Except` or what have you) would result in something that's less efficient than just looping yourself. If the list was sorted on `(CategoryId, SectionId)`, then a more efficient algorithm is possible -- but of course sorting consumes time itself. – Jeroen Mostert Jan 25 '17 at 20:22

5 Answers5

3
Products.RemoveAll(x => ProductsToRemove
    .Any(r => x.CategoryId == r.CategoryId && x.SectionId == r.SectionId));
chadnt
  • 1,095
  • 9
  • 24
1

You can use Where() in combination of Any() to achieve the required output:

var deletion = Products
   .Where(product=> ProductsToRemove
                   .Any(remove=> product.CategoryId == remove.CategoryId 
                                 && product.SectionId == remove.SectionId
                       )
          );
Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
0
List<Product> Products = new List<Product>()
{
   new Product() { Id = 1, Name = "A", CategoryId = 11, SectionId = 6, VendorName = "ABC" },
   new Product() { Id = 2, Name = "B", CategoryId = 21, SectionId = 6, VendorName = "ABC" },
   new Product() { Id = 3, Name = "C", CategoryId = 13, SectionId = 8, VendorName = "ABC" },
   new Product() { Id = 4, Name = "D", CategoryId = 90, SectionId = 6, VendorName = "ABC" },
   new Product() { Id = 5, Name = "E", CategoryId = 25, SectionId = 9,    VendorName = "ABC" },
};

List<Product> catsRemoved = Products.Where(x => x.CategoryId != 11 && x.CategoryId != 90).ToList();
0

You could use the Linq except method: https://msdn.microsoft.com/en-us/library/bb300779(v=vs.110).aspx

Theo
  • 885
  • 6
  • 16
0

For those who don't mind changing their data type.

If keys are not allowed to collide in your set than you can just use a normal Dictionary. Or implement Equals and use a HashSet (Note that HashSet is a set, not a list)

If keys may collide you can do this with a dictionary of lists.

Here is an example of what I mean.

Dictionary<string, List<Product>> Products = default;
List<Product> l = default.GetOrDefault(p.id1+"<|>"+p.id2); //LinQ extension on map
l.Clear();

Of course, you can always wrap this up in a class to disguise it as a List, probably with an actual list also in it to preserve order.

Tezra
  • 8,463
  • 3
  • 31
  • 68