LaserBeak
LaserBeak

Reputation: 3285

Lambda or LinQ expression to remove certain objects from List

I have a cart.Lines List and want to remove all items where quantity == 0

This is a list that holds collection of CartLine objects:

public class Cart
{
    private IList<CartLine> lines = new List<CartLine>();
    public IList<CartLine> Lines { get { return lines; } set { lines = value; } }
}   

public class CartLine
{
    Product Product {get; set;}
    int Quantity {get; set;}

}

So something like:

cart.Lines.RemoveAll(x => x.Quantity == 0)

I only get Remove and RemoveAt, not RemoveAll !

Also can't remove in a foreach loop, get error: Collection was modified; enumeration operation may not execute.

I have now managed to do it with this code, surely there must be something more efficient ?

var myList = cart.Lines.ToList();
myList.RemoveAll(x => x.Quantity == 0);
cart.Lines = myList;

Okay Problem solved!Thanks guys, this here does it:

cart.Lines = cart.Lines.Where(x => x.Quantity != 0);

Upvotes: 3

Views: 12847

Answers (6)

Security Hound
Security Hound

Reputation: 2551

I will go ahead and post my suggestion to this problem.

private IList<CartLine> lines = new List<CartLine>(); 

should be:

private List<CartLine> lines = new List<CartLine>(); 

This will allow you to use the suggested method of:

cart.Lines.RemoveAll(x => x.Quantity == 0);  

You do exactly that by doing it this way:

var myList = cart.Lines.ToList();       
myList.RemoveAll(x => x.Quantity == 0);              
cart.Lines = myList;   

Upvotes: 1

James Michael Hare
James Michael Hare

Reputation: 38397

If Lines is a List<T>, then the simplest way is to just write:

cart.Lines.RemoveAll(x => x.Quantity == 0);

If Lines is an IEnumerable<T>, though, you could select the negative (as Vlad suggested) - you could also change to a list using ToList() and then do RemoveAll() but that would be overkill.

cart.Lines = cart.Lines.Where(x => x.Quantity != 0);

UPDATE:

Since you said Lines is an IList<T>, then you will want to select the negative and convert to a list like:

cart.Lines = cart.Lines.Where(x => x.Quantity != 0).ToList();

Or you can conver to a List<T> using ToList() then call RemoveAll() and then save back:

var temp = cart.Lines.ToList();
temp.RemoveAll(x => x.Quantity != 0);
cart.Lines = temp;

Incidentally, as an FYI I timed both building a remove list and then using Remove() vs selecting the negative using Where() and calling ToList() and the Where/ToList combo was much faster which makes sense because both allocate memory, but the Where/ToList does a lot less memory shuffling.

Here's the timing for removing all the even numbers out of a list of 100,000 ints:

  • Removing all evens building a remove list and calling Remove() on each took: 3921 ms
  • Removing all evens using Where() on negative and then ToList() took: 2 ms
  • Removing all evens using ToList() on original then RemoveAll() took: 1 ms

Upvotes: 7

Alex Mendez
Alex Mendez

Reputation: 5150

You can do it as follows:

Cart cart = new Cart();
List<CartLine> cartLines = cart.Lines.ToList<CartLine>();
cartLines.RemoveAll(x => x.Quantity == 0);
cart.Lines = cartLines;

Also, you should set the CartLine Quantity and Product properties as public.

Upvotes: 0

Vlad Bezden
Vlad Bezden

Reputation: 89527

var myResult = cart.Lines.Where(x => x.Quantity > 0)

Alternatively you can use RemoveAll

cart.Lines.RemoveAll(x => x.Quantity == 0)

Check this post that answers your question C# using LINQ to remove objects within a List

Upvotes: 1

Franchesca
Franchesca

Reputation: 1463

These queries essentially foreach over a list, and as you know, you shouldn't use them to directly modify the list. Rather you should make a list of the items to be removed using the query, and then remove them in a separate operation.

EDIT:

yeh, I forgot you can use RemoveAll to do this in one line :D

Upvotes: 1

treetey
treetey

Reputation: 829

Assuming that cart.Lines is List<>: cart.Lines.RemoveAll(x => x.Quantity == 0);

Upvotes: 3

Related Questions