How to remove items in IEnumerable<MyClass>? - c#

How do I remove items from a IEnumerable that match specific criteria?
RemoveAll() does not apply.

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.

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.

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);

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.

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;
}
}

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.

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

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

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

Related

C# Interface IEnumerable Any() without specifying generic types

I have casted
var info = property.Info;
object data = info.GetValue(obj);
...
var enumerable = (IEnumerable)data;
if (enumerable.Any()) ///Does not compile
{
}
if (enumerable.GetEnumerator().Current != null) // Run time error
{
}
and I would like to see if this enumerable has any elements, via using Linq Query Any(). But unfortunately, even with using Linq, I can't.
How would I do this without specifying the generic type.
While you can't do this directly, you could do it via Cast:
if (enumerable.Cast<object>().Any())
That should always work, as any IEnumerable can be wrapped as an IEnumerable<object>. It will end up boxing the first element if it's actually an IEnumerable<int> or similar, but it should work fine. Unlike most LINQ methods, Cast and OfType target IEnumerable rather than IEnumerable<T>.
You could write your own subset of extension methods like the LINQ ones but operating on the non-generic IEnumerable type if you wanted to, of course. Implementing LINQ to Objects isn't terribly hard - you could use my Edulinq project as a starting point, for example.
There are cases where you could implement Any(IEnumerable) slightly more efficiently than using Cast - for example, taking a shortcut if the target implements the non-generic ICollection interface. At that point, you wouldn't need to create an iterator or take the first element. In most cases that won't make much performance difference, but it's the kind of thing you could do if you were optimizing.
One method is to use foreach, as noted in IEnumerable "Remarks". It also provides details on the additional methods off of the result of GetEnumerator.
bool hasAny = false;
foreach (object i in (IEnumerable)(new int[1] /* IEnumerable of any type */)) {
hasAny = true;
break;
}
(Which is itself easily transferable to an Extension method.)
Your attempt to use GetEnumerator().Current tried to get the current value of an enumerator that had not yet been moved to the first position yet. It would also have given the wrong result if the first item existed or was null. What you could have done (and what the Any() in Enumerable does) is see if it was possible to move to that first item or not; i.e. is there a first item to move to:
internal static class UntypedLinq
{
public static bool Any(this IEnumerable source)
{
if (source == null) throw new ArgumentNullException(nameof(source));
IEnumerator ator = source.GetEnumerator();
// Unfortunately unlike IEnumerator<T>, IEnumerator does not implement
// IDisposable. (A design flaw fixed when IEnumerator<T> was added).
// We need to test whether disposal is required or not.
if (ator is IDisposable disp)
{
using(disp)
{
return ator.MoveNext();
}
}
return ator.MoveNext();
}
// Not completely necessary. Causes any typed enumerables to be handled by the existing Any
// in Linq via a short method that will be inlined.
public static bool Any<T>(this IEnumerable<T> source) => Enumerable.Any(source);
}

Cast generic Collection to List once, then RemoveAt multiple times

I have a generic collection of objects as a property of an object. This data comes from a sql query and api. I want to use the RemoveAt method to remove some of them efficiently. But Visual Studio complains to me that the RemoveAt method is undefined. My intuition is to cast the Collection to a List, giving me access to the RemoveAt method. I only want to cast one time, then use RemoveAt as many times as necessary. I could use the Remove(object) command, but it requires traversing the Collection to look for the object for each call, which is slower than using RemoveAt
Here is what I'm trying:
obj.stuckArray = obj.stuckArray.ToList();
After this line, I have a line of code that looks like this:
obj.stuckArray.RemoveAt(1);
Unfortunately the RemoveAt gets underlined with red and the warning from Visual Studio reads: "ICollection does not contain a definition for 'RemoveAt'"
Is it possible to cast once and RemoveAt multiple? Or is this not possible?
Just do it in three statements instead of two, using a local variable:
var list = obj.stuckArray.ToList();
list.RemoveAt(1);
obj.stuckArray = list;
That way the type of stuckArray doesn't matter as much: you only need to be able to call ToList() on it. The RemoveAt method on List<T> is fine because that's the type of list.
Obviously you want to remove an element from the array and store it back into the original member stuckArray. However as an Icollection has no method RemoveAt defined, you get the error. The method however exists on List<T>.
So do the following instead:
var tmp = obj.stuckArray.ToList();
tmp.RemoveAt(1);
obj.stuckArray = tmp;
However this will traverse the entire collection anyway, as ToList will copy the entire collection into a new one. But I don´t see any way around this in order to delete an element from your array, because an array has no RemoveAt-method.
As per your EDIT: why not just make the Remove after the re-definition of your stuckArray:
var tmp = obj.stuckArray.ToList();
obj.stuckArray = tmp;
Now you can call RemoveAt as often as you want:
((List<MyType>)obj.stuckArray).RemoveAt(1);
((List<MyType>)obj.stuckArray).RemoveAt(1);
((List<MyType>)obj.stuckArray).RemoveAt(1);
Casting this so many times shouldn´t have a big impact on your performance, as obj.stuckArray already is a List<MyType>. RemoveAt on the other hand will have an effect here, as the method will copy the internal array, as you can see at the source-code for RemoveAt:
public void RemoveAt(int index) {
if ((uint)index >= (uint)_size) {
ThrowHelper.ThrowArgumentOutOfRangeException();
}
Contract.EndContractBlock();
_size--;
if (index < _size) {
Array.Copy(_items, index + 1, _items, index, _size - index); // here the entire array will be traversed again
}
_items[_size] = default(T);
_version++;
}
So by calling RemoveAt three times, you also copy the internal array three times.
If you have control over the object that exposes the struckArray property,
you can expose stuckArray as ICollection<T>, but inside the object use a List<T> as it's backing field. Then you can add a method that removes an item by it's index:
class MyClass
{
private list<int> _stuckArray; // of course, this doesn't have to be int...
public ICollection<int> StuckArray {get {return _stuckArray;}}
public RemoveFromStuckArray(int index)
{
_stuckArray.RemoveAt(index);
}
}
That will enable you to keep whatever references you already have to the property, and also supply a method to remove items by their indexes efficiently, though I'm not sure that's such a good idea to enable removing items by indexes from an ICollection in the first place.

LINQ: Transforming items in a collection

Is there a LINQ method to modify items in a collection, such as simply setting a property of each item in a collection? Something like this:
var items = new []{ new Item { IsActive = true } }
var items = items.Transform(i => i.IsActive = false)
where Touch enumerates each item and applies the transformation. BTW, I am aware of the SELECT extension method, but this would require I expose a method on the type that does this transformation and return the same reference.
var items = items.Select(i => i.Transform())
where Item.Transform returns does the transformation and return the same instance.
TIA
No, there are no methods in standard LINQ that allows you to modify items in a collection. LINQ is for querying collections and not for causing side-effects (e.g., mutating the items). Eric Lippert goes into the idea in more detail in his blog post: “foreach” vs “ForEach”.
Just use a loop.
foreach (var item in items)
{
item.IsActive = false;
}
LINQ is for querying. Use a simple loop if you want to modify. Just use the right tool for the right job. LINQ is not a messiah for everything.
There's a ForEach() on List, so you can do items.ToList().ForEach(i => i.IsActive = false). You might want to read this though.
The documentation page on MSDN for the Enumerable class lists all LINQ methods, and unfortunately no method there does what you want. LINQ is a query language and is not intended to modify collections. It is functional in its nature, meaning that it doesn't modify the collection it operates on, rather it returns a new enumerable.
For your purposes it is better to simply use a foreach loop, or if you feel the need write your own extension method to do what you want, eg.
public static void ForEach<T>(this IEnumerable<T> seq, Action<T> action)
{
foreach (T item in seq)
action(item);
}
which could then be used as you wanted:
items.ForEach(i => i.IsActive = false)

How to get an empty list of a collection?

I have a collection of anonymous class and I want to return an empty list of it.
What is the best readable expression to use?
I though of the following but I don't think they are readably enough:
var result = MyCollection.Take(0).ToList();
var result = MyCollection.Where(p => false).ToList();
Note: I don't want to empty the collection itself.
Any suggestion!
Whats about:
Enumerable.Empty<T>();
This returns an empty enumerable which is of type T. If you really want a List so you are free to do this:
Enumerable.Empty<T>().ToList<T>();
Actually, if you use a generic extension you don't even have to use any Linq to achieve this, you already have the anonymous type exposed through T
public static IList<T> GetEmptyList<T>(this IEnumerable<T> source)
{
return new List<T>();
}
var emp = MyCollection.GetEmptyList();
Given that your first suggestion works and should perform well - if readability is the only issue, why not create an extension method:
public static IList<T> CreateEmptyCopy(this IEnumerable<T> source)
{
return source.Take(0).ToList();
}
Now you can refactor your example to
var result = MyCollection.CreateEmptyCopy();
For performance reasons, you should stick with the first option you came up with.
The other one would iterate over the entire collection before returning an empty list.
Because the anonymous type there is no way, in source code, to create a list. There is, however, a way to create such list through reflection.

List(T) RemoveAll() not working as intended...?

Let's say I have a list of User objects with two properties...ID and Name
List<User> lst = List<User>();
I fill it up with a bunch of Users. Ok, now I want to trim my list using RemoveAll() and this function.
private Boolean IsExisting(int id) {
//blah blah
return true;
//blah blah
return false;
}
So I use this statement:
gdvFoo.DataSource = lst.RemoveAll(t => IsExisting(t.ID));
It is my understanding that whenever IsExisting returns true that element should be removed from lst, but what happens, strangely enough, is it returns an integer?, not a truncated list and I received the following error message:
Data source is an invalid type. It must be either an IListSource, IEnumerable, or IDataSource.>
List.RemoveAll method
The method removes all matching instances from the list on which you called it. This modifies the existing list, rather than returning a new one.
The return value is the number of rows removed.
RemoveAll() returns the number of elements removed.
You need to do this:
lst.RemoveAll(t => IsExisting(t.ID));
gdvFoo.DataSource = lst;
The docs are very clear about what's going on:
Return Value
Type: System.Int32
The number of elements removed from the List .
Perhaps the following Linq would be more in line with your expectations?
lst.Except(t => IsExisting(t.ID)).ToList();
Instead of RemoveAll(), you could try using IEnumerable's filter where you would say something like :
var filteredList = lst.Where(item => IsExisting(item.Id))
This makes the code a little more easier to read and focusses on the objective of the task at hand, rather than how to look at implementing it.
List<T>.RemoveAll(...) has a return type of int which is not an IListSource, IEnumerable nor IDataSource
The RemoveAll is modifying the list and returning the number of items removed. You just set your datasource to the list in a second step.
lst.RemoveAll(t => IsExisting(t.ID));
gdvFoo.DataSource = lst;

Categories

Resources