tags:

views:

1886

answers:

5

Now I come a stage to get all my data as a list in cache(objects) and my next thing I have to do is to remove some instances from the list.

Normally, I would do removing like this:

List<T> list;
List<T2> toBeRemovedItems;
// populate two lists
foreach(T2 item in toBeRemovedItems)
{
  list.Remove(delegate(T one) { 
    // build a condition based on item
    // return true or false
    });
}

To be more specific, I actually build or populate toBeRemvoedItems list of a dynamic class (not a formal defined class). For example, the T class is something like MyClass and codes for removing are:

class MyClass<C> {
  public string Value1 { get; set; }
  public int Value2 { get; set; }
  public C ObjectC { get; set; }
}
....
List<MyClass<C>> list;
// populate list
// populate toBeRemovedItems. Here is an example of hard-coded codes:
var toBeRemovedLItems = new[] {
  new { Value1="a", Value2 = 1},
  new { Value2="x", Value2 = 10},
  ...
  };
// toBeRemovedItems may be the result of Select from a collection
foreach(var item in toBeRemovedLItems)
{
   list.Remove(delegate(MyClass one) {
        return one.Value1 = item.Value1 &&
            one.Value2 < item.Value2;
      });
 }

I tried to search for Remove() method in IEnumerable interface from MSDN, but I cannot find the method of Remove() there (it makes sense that IEnumerable is used just for enumeration). In List class, there are several overloaded Remove(...) methods. I am not sure if there any alternative ways to remove items from a list by using LINQ or Lambda expressions?

By the way, I thought about a way to do a query against a list to get a subset or a new IEnumerable list with Where conditions, similar as moving items from a list. However, I prefer to remove items from my cached list, and there some cases I just cannot reset list property in a class to a new list (private set for example).

+3  A: 

You could use the method RemoveAll:

MyClass one; //initialize MyClass
list.RemoveAll(item => one.Value1 == item.Value1 && one.Value2 < item.Value2);
Francis B.
i think it's actually a method of List<T>, not an extension method
Jimmy
Thanks! I update my post.
Francis B.
My understanding your codes is that you remove one item at a time. Still I have to loop each just like Rchard Hein's suggestion.
David.Chu.ca
+2  A: 
foreach(var item in toBeRemovedLItems) {   
   list.RemoveAll(one => one.Value1 == item.Value1 && one.Value2 < item.Value2); 
}

Too late again. Oh well.

Richard Hein
Not sure if it is possible to pass two parameters to the RemoveAll(lambda func) to remove a toBeRemovedItems, without through foreach loop. For sure it is already very readable.
David.Chu.ca
+5  A: 

You can use LINQ's Where method to filter out values that should not be a part of the list. The result is an IEnumerable<T> with the elements removed.

var res = list.Where(item => !(one.Value1 == item.Value1 && one.Value2 < item.Value2));

This will not updated the original List<T> instance but instead will create a new IEnumerable<T> with the values removed.

JaredPar
+1  A: 

I agree with Jared's suggestion of filtering out certain items, but it looks like a join on Value1 would be a more efficient approach:

var res = from item1 in list
          join item2 in toBeRemovedList
            on item1.Value1 equals item2.Value1
          where item1.Value2 >= item2.Value2
          select item1;

Update: Apparently I fail at reading comprehension - new approach:

var removeDict = toBeRemovedList.ToDictionary(i => i.Value1, i => i.Value2);
list.RemoveAll(item => {
    int itemToRemoveValue2;
    if(removeDict.TryGetValue(item.Value1, out itemToRemoveValue2))
        return item.Value2 < itemToRemoveValue2;
    return false;
});

Of course, it would be even better if your list to remove could start as a dictionary. Ultimately, we're just trying to make our match on Value1 more efficient.

dahlbyk
Is the join similar as SQL Intersect? or this LINQ query like that?
David.Chu.ca
Anyway, as I mentioned in my question, if the list property is not settable, I cannot use this strategy. It is good way only I have control the list.
David.Chu.ca
Noted - answer updated.
dahlbyk
A: 

If I get the question correctly, to produce a unique set from two List.

For this, you can use the following

List list1; List list2;

List list3 = list1.Except(list2)

The list3 will contain unique items.