Is it possible to implement RemoveAll() on EntityCollection<T>? - c#

I have a question similar to this one, but pertaining to EntityCollection<>.
EntityCollection implements Remove(), allowing you to remove a single item from the list at once. However, I'd like to implement an extension method that can remove multiple items at once, similar to IList<T>'s RemoveAll(Predicate<T> match) method.
One idea would be to loop through the list, and remove items. Something like:
public static void RemoveAll<T>(this EntityCollection<T> collection, Predicate<T> match) where T : EntityObject
{
foreach (T o in collection)
{
if (match(o))
collection.Remove(o);
}
}
However, this will throw an exception because you can't modify the collection you're iterating through.
Another idea would be to build a temporary list of items to remove, then loop through that list and remove each item from the collection. However, this seems inefficient to me. Is there a better implementation?

As I said in comments, iterating over a secondary list is probably the only safe choice here.
You can implement it with something like:
public static void RemoveAll<T>(this EntityCollection<T> collection,
Predicate<T> match) where T : EntityObject
{
if (match == null) {
throw new ArgumentNullException("match");
}
collection.Where(entity => match(entity))
.ToList().ForEach(entity => collection.Remove(entity));
}

Related

how to convert user defined data type to hashset c#

I have user defined type Items which inherits IList, ICollection, IEnumerable. How to convert this type to HashSet<Items>. I am using below snippet, is there any efficient way to this?
public static class Extensions
{
public static bool AddRange<T>(this HashSet<T> #this, IEnumerable<T> items)
{
bool allAdded = true;
foreach (T item in items)
{
added &= #this.Add(item);
}
return allAdded;
}
}
A HashSet<T> has a constructor which accepts an IEnumerable<T> and instantiates that HashSet from the collection. You could simply call that.
If you want to load the items in your custom type into an existing HashSet, you'd probably want to use the HashSet's UnionWith method, which:
Modifies the current HashSet object to contain all elements that are present in itself, the specified collection, or both.
What these two options won't do, however, is give you a result specifying if any items didn't make it through the conversion. You'd be able to do it later, though, by calling one of HashSet's other methods, such as IsSupersetOf, or simply comparing Counts.

How can I convert an IEnumerable<MyType> into a MyList<MyType>?

I have a custom List MyList that is an extension of List, and I have an IEnumerable (or IQueryable) which I want to do .ToList() on, but I guess, .ToMyList().
How can I implement the ToList() method? The source code for ToList() is to create a new List() and pass in the IEnumerable as a parameter, but I am not sure what it does with it.
If your class subclasses List<T>, and you provide the correct constructor, you should be able to do:
MyList<MyType> list = new MyList<MyType>(theEnumerable);
If you want a simple extension method, similar to Enumerable.ToList, you could write your own:
public static MyList<T> ToMyList<T>(this IEnumerable<T> theEnumerable)
{
return new MyList<T>(theEnumerable);
}
You could then call this via:
var list = theEnumerable.ToMyList();
Note that subclassing List<T>, in general, is really not a very good idea. You should really consider subclassing Collection<T> and implementing IList<T>, if you need a custom collection, instead. You can still provide the same constructors and use the methods above to populate the custom collection, if required.
If you have a base class and you are able to delegate list population to its constructor, do that:
public MyList(IEnumerable<MyType> items) : base(items) { }
Otherwise, this constructor should work for almost any collection class:
public MyList(IEnumerable<MyType> items)
{
if (items == null)
throw new ArgumentNullException("items");
foreach (var item in items)
Add(item);
}
Then you can write an extension method, or call this constructor directly to populate a new list from a sequence.

Is it possible to determine if an IEnumerable<T> has deffered execution pending?

I have a function that accepts an Enumerable. I need to ensure that the enumerator is evaluated, but I'd rather not create a copy of it (e.g. via ToList() or ToArray()) if it is all ready in a List or some other "frozen" collection. By Frozen I mean collections where the set of items is already established e.g. List, Array, FsharpSet, Collection etc, as opposed to linq stuff like Select() and where().
Is it possible to create a function "ForceEvaluation" that can determine if the enumerable has deffered execution pending, and then evaluate the enumerable?
public void Process(IEnumerable<Foo> foos)
{
IEnumerable<Foo> evalutedFoos = ForceEvaluation(foos)
EnterLockedMode(); // all the deferred processing needs to have been done before this line.
foreach (Foo foo in foos)
{
Bar(foo);
}
}
public IEnumerable ForceEvaluation(IEnumerable<Foo> foos)
{
if(??????)
{ return foos}
else
{return foos.ToList()}
}
}
After some more research I've realized that this is pretty much impossible in any practical sense, and would require complex code inspection of each iterator.
So I'm going to go with a variant of Mark's answer and create a white-list of known safe types and just call ToList() anything not on that is not on the white-list.
Thank you all for your help.
Edit*
After even more reflection, I've realized that this is equivalent to the halting problem. So very impossible.
Something that worked for me way :
IEnumerable<t> deffered = someArray.Where(somecondition);
if (deffered.GetType().UnderlyingSystemType.Namespace.Equals("System.Linq"))
{
//this is a deffered executin IEnumerable
}
You could try a hopeful check against IList<T> or ICollection<T>, but note that these can still be implemented lazily - but it is much rarer, and LINQ doesn't do that - it just uses iterators (not lazy collections). So:
var list = foos as IList<Foo>;
if(list != null) return list; // unchanged
return foos.ToList();
Note that this is different to the regular .ToList(), which gives you back a different list each time, to ensure nothing unexpected happens.
Most concrete collection types (including T[] and List<T>) satisfy IList<T>. I'm not familiar with the F# collections - you'd need to check that.
I would avoid it if you want to make sure it is "frozen". Both Array elements and List<> can be changed at any time (i.e. infamous "collection changed during iteration" exception). If you really need to make sure IEnumerable is evaluated AND not changing underneath your code than copy all items into your own List/Array.
There could be other reasons to try it - i.e. some operations inside run time do special checks for collection being an array to optimize them. Or have special version for specialized interface like ICollection or IQueryable in addition to generic IEnumerable.
EDIT: Example of collection changing during iteration:
IEnumerable<T> collectionAsEnumrable = collection;
foreach(var i in collectionAsEnumrable)
{
// something like following can be indirectly called by
// synchronous method on the same thread
collection.Add(i.Clone());
collection[3] = 33;
}
If it is possible to use a wrapper in your case, you could do something like this
public class ForceableEnumerable<T> : IEnumerable<T>
{
IEnumerable<T> _enumerable;
IEnumerator<T> _enumerator;
public ForceableEnumerable(IEnumerable<T> enumerable)
{
_enumerable = enumerable;
}
public void ForceEvaluation()
{
if (_enumerator != null) {
while (_enumerator.MoveNext()) {
}
}
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
_enumerator = _enumerable.GetEnumerator();
return _enumerator;
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
Or implement the force method like this if you want to evaluate in any case
public void ForceEvaluation()
{
if (_enumerator == null) {
_enumerator = _enumerable.GetEnumerator();
}
while (_enumerator.MoveNext()) {
}
}
EDIT:
If you want to ensure that the enumeration is evaluated only once in any case, you could change GetEnumerator to
public IEnumerator<T> GetEnumerator()
{
if (_enumerator == null) }
_enumerator = _enumerable.GetEnumerator();
}
return _enumerator;
}

RemoveAll for ObservableCollections?

I am looking for Linq way (like RemoveAll method for List) which can remove selected items from my ObservableCollection.
I am too new to create an extension method for myself. Is there any way I remove items from ObservableCollection passing a Lambda expression?
I am not aware of a way to remove only the selected items. But creating an extension method is straight forward:
public static class ExtensionMethods
{
public static int Remove<T>(
this ObservableCollection<T> coll, Func<T, bool> condition)
{
var itemsToRemove = coll.Where(condition).ToList();
foreach (var itemToRemove in itemsToRemove)
{
coll.Remove(itemToRemove);
}
return itemsToRemove.Count;
}
}
This removes all items from the ObservableCollection that match the condition. You can call it like that:
var c = new ObservableCollection<SelectableItem>();
c.Remove(x => x.IsSelected);
Iterating backwards should be more efficient than creating a temporary collection as in Daniel Hilgarth's example.
public static class ObservableCollectionExtensions
{
public static void RemoveAll<T>(this ObservableCollection<T> collection,
Func<T, bool> condition)
{
for (int i = collection.Count - 1; i >= 0; i--)
{
if (condition(collection[i]))
{
collection.RemoveAt(i);
}
}
}
}
How about this implementation for a one-liner?
observableCollection.Where(l => l.type == invalid).ToList().All(i => observableCollection.Remove(i))
-- Edit --
Sorry, yes, you need a ToList() in the middle to force the first half to evaluate, as LINQ does lazy evaluation by default.
Each of solution proposed here which uses routine to remove item one by one has one fault. Imagine that you have many items in observable collection, lets say 10.000 items. Then you want to remove items which meets some condition.
If you use solution from Daniel Hilgarth and call: c.Remove(x => x.IsSelected); and there are for example 3000 items to be removed, proposed solution will notify about each item removal. This is due to fact that internal implementation of Remove(item) notify about that change. And this will be called for each of 3000 items in removal process.
So instead of this i created descendant of ObservableCollection and add new method RemoveAll(predicate)
[Serializable]
public class ObservableCollectionExt<T> : ObservableCollection<T>
{
public void RemoveAll(Predicate<T> predicate)
{
CheckReentrancy();
List<T> itemsToRemove = Items.Where(x => predicate(x)).ToList();
itemsToRemove.ForEach(item => Items.Remove(item));
OnPropertyChanged(new PropertyChangedEventArgs("Count"));
OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
Interesting line is itemsToRemove.ForEach(item => Items.Remove(item));. Calling directly Items.Remove(item) will not notify about item removed.
Instead after removal of required items, changes are notified at once by calls:
OnPropertyChanged(new PropertyChangedEventArgs("Count"));
OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
This is my version of an extension method solution, which is only a slight variation on the accepted answer, but has the advantage that the count returned is based on confirmed removal of the item from the collection:
public static class ObservableCollectionExtensionMethods
{
/// <summary>
/// Extends ObservableCollection adding a RemoveAll method to remove elements based on a boolean condition function
/// </summary>
/// <typeparam name="T">The type contained by the collection</typeparam>
/// <param name="observableCollection">The ObservableCollection</param>
/// <param name="condition">A function that evaluates to true for elements that should be removed</param>
/// <returns>The number of elements removed</returns>
public static int RemoveAll<T>(this ObservableCollection<T> observableCollection, Func<T, bool> condition)
{
// Find all elements satisfying the condition, i.e. that will be removed
var toRemove = observableCollection
.Where(condition)
.ToList();
// Remove the elements from the original collection, using the Count method to iterate through the list,
// incrementing the count whenever there's a successful removal
return toRemove.Count(observableCollection.Remove);
}
}
There is no way to pass an expression to the ObservableCollection to remove matching items, in the same way that a generic list has. ObservableCollection adds and removes one item at a time.
You will have to create your own implementation of INotifyCollectionChanged in order to do this, or as you mention create an extension method.
ObservableCollection<AppVariable<G>> _appVariables = new new ObservableCollection<AppVariable<G>>();
var temp = AppRepository.AppVariables.Where(i => i.IsChecked == true).OrderByDescending(k=>k.Index);
foreach (var i in temp)
{
AppRepository.AppVariables.RemoveAt(i.Index);
}
Kinda late but just posting this up here since I couldn't find another solution online while I ran into this same issue:
obj objToRemove = Collection.First(obj => obj.ID == ID);
Collection.Remove(objToRemove);
Assuming u have an ID or Name of sorts where u can get your desired object to remove, you can use the '.First' method from ObservableCollections to get your object to remove and call the '.Remove' method to remove the selected item.
Alternatively, you can just throw the entire first line into the Remove method.
Collection.Remove(Collection.First(obj => obj.ID == ID));

T in class? AddRange ICollection?

I try to do static class, add to icollection but i got some issues i cant seem to overcome. that is how i get so i can pass a ICollection in the method? cause T is that say it can not be resolved.
and then i wonder is there a way to do AddRange on icollection?
i was thinking of something like this but maby i am way out of my mind with it?
public static ICollection<T> add(this IEnumerable<T> list)
{
ICollection<T> collection = null;
return collection.AddRange(list);
}
No, ICollection<T> doesn't have an AddRange method - and even if it did, you'd be trying to dereference null which will throw a NullReferenceException. You haven't specified a collection to add the list to... what exactly are you trying to do?
You could create (say) a new List<T> - and that has the benefit of already having a constructor which can take an IEnumerable<T>:
public static ICollection<T> Add<T>(this IEnumerable<T> list)
{
return new List<T>(list);
}
However, at that point you've really just reimplemented Enumerable.ToList() and given it a different return type...
If you want to add everything to an existing collection, you might want something like this:
public static ICollection<T> AddTo<T>(this IEnumerable<T> list,
ICollection<T> collection)
{
foreach (T item in list)
{
collection.Add(item);
}
return collection;
}
If I understand correctly you want to add a IEnumerable<T> to an empty collection.
Wouldn't it be easier to just do:
ICollection<MyObject> collection = new List<MyObject>(GetIEnumerableOfMyObject());
Or even:
ICollection<MyObject> collection = GetIEnumerableOfMyObject().ToList();
The other ways seem to assume that your ICollection is empty and/or your ICollection is a type of List. However, if you want AddRange, then you can Extend the ICollection class as follows:
public static void AddRange<T>(this ICollection<T> ic, IEnumerable<T> ie)
{
foreach (T obj in ie)
{
ic.Add(obj);
}
}
Note, however, that since List impliments ICollection, this may cause ambiguity when dealing directly with List objects (though I haven't tested yet if the compiler will be able to resolve it--my gut reaction is that it should, though, since AddRange is a member of List and the compiler will go through member functions first before looking at extensions, but if I'm wrong I'm sure someone will correct me).
Depending on the collection type of your source list an alternative approach is to use List(T).ForEach, as in:
List<string> source = ...
ICollection<string> dest = ...
source.Foreach(dest.Add);
However, the readability of this is easy to dispute.

Categories