3

How do I remove items from a IEnumerable that match specific criteria?

RemoveAll() does not apply.

4thSpace
  • 43,672
  • 97
  • 296
  • 475

9 Answers9

12

You can't; IEnumerable as an interface does not support removal.

If your IEnumerable instance is actually of a type that supports removal (such as List<T>) then you can cast to that type and use the Remove method.

Alternatively you can copy items to a different IEnumerable based on your criteria, or you can use a lazy-evaluated query (such as with Linq's .Where) to filter your IEnumerable on the fly. Neither of these will affect your original container, though.

Dan Puzey
  • 33,626
  • 4
  • 73
  • 96
  • In my case, the code was executing `.Aggregate` on the `IEnumerable`. I inserted a `.Where` filter as Dan suggested, eg. `foo.Where(condition).Aggregate(expression)`. It worked like a charm. – Codes with Hammer Aug 15 '17 at 14:00
3

This will produce a new collection rather than modifying the existing one however I think it is the idiomatic way to do it with LINQ.

    var filtered = myCollection.Where(x => x.SomeProp != SomValue);

Another option would be to use Where to produce a new IEnumerable<T> with references to the objects you want removed then pass that to a Remove call on the original collection. Of course that would actually consume more resources.

evanmcdonnal
  • 46,131
  • 16
  • 104
  • 115
1

You can't remove items from an IEnumerable<T>. You can remove items from an ICollection<T> or filter items from an IEnumerable<T>.

// filtering example; does not modify oldEnumerable itself
var filteredEnumerable = oldEnumerable.Where(...);
// removing example
var coll = (ICollection<MyClass>)oldEnumerable;
coll.Remove(item);
Tim S.
  • 55,448
  • 7
  • 96
  • 122
1

You don't remove items from an IEnumerable. It's not possible. It's just a sequence of items. You can remove items from some underlying source that generates the sequences, for example if the IEnumerable is based on a list you can remove items from that list.

The other option you have is to create a new sequence, based on this one, that never shows the given items. You can do that using Where, but it's important to realize this isn't removing items, but rather choosing to show items based on a certain condition.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • It's not impossible. @TimS. alluded to it in his answer. Also see my answer on another question about a similar topic at http://stackoverflow.com/a/15858794/425871 – Steve Nov 25 '13 at 18:18
  • @Steve As I *stated* in my answer, you can remove items from some collection that is the underlying data source for an `IEnumerable`. That's still not removing items from an `IEnumerable` though, that's removing items from the underlying data source. – Servy Nov 25 '13 at 18:22
  • 1
    Your right - I didn't read your answer quite closely enough :) – Steve Nov 25 '13 at 18:23
1

As everyone has already stated, you can't remove from IEnumerable because that is not what the interface is describing. Consider the following example:

public IEnumerable<string> GetSomeStrings()
{
    yield return "FirstString";
    yield return "Another string";
}

Clearly, removing an element from this IEnumerable is not something you can reasonably do, instead you'd have to make a new enumeration without the ones you don't want.

The yield keywork provides other examples, for example, you can have infinite lists:

public IEnumberable<int> GetPowersOf2()
{
    int value = 1;
    while(true)
    {
        yield return value;
        value = value * 2;
    }
}
T. Kiley
  • 2,752
  • 21
  • 30
0

Items cannot be removed from an IEnumerable<T>. From the documentation:

Exposes the enumerator, which supports a simple iteration over a collection of a specified type.

Lasse Christiansen
  • 10,205
  • 7
  • 50
  • 79
0

You can cast it and use the List<T>.RemoveAll(Predicate<T> match) this is exactly what you need.

Bassam Alugili
  • 16,345
  • 7
  • 52
  • 70
0

This is how i do,

IEnumerable<T> myVar=getSomeData(); // Assume mayVar holds some data

myVar=myVar.Where(d=>d.Id>10); // thats all, i want data with Id>10 only
-1

How about trying Enumerable.Empty i.e.

T obj = new T();
IEnumerable<T> myVar = new T[]{obj}    //Now myVar has an element
myVar = Enumerable.Empty<T>();        //Now myVar is empty