Two that I like to use are the InsertWhere<T
> and RemoveWhere<T
> Extension Methods that I've written. Working with ObservableCollections in WPF and Silverlight I often need to modify ordered lists without recreating them. These methods allow me to insert and remove according to a supplied Func, so .OrderBy() doesn't need to be re-called.
/// <summary>
/// Removes all items from the provided <paramref name="list"/> that match the<paramref name="predicate"/> expression.
/// </summary>
/// <typeparam name="T">The class type of the list items.</typeparam>
/// <param name="list">The list to remove items from.</param>
/// <param name="predicate">The predicate expression to test against.</param>
public static void RemoveWhere<T>(this IList<T> list, Func<T, bool> predicate)
{
T[] copy = new T[] { };
Array.Resize(ref copy, list.Count);
list.CopyTo(copy, 0);
for (int i = copy.Length - 1; i >= 0; i--)
{
if (predicate(copy[i]))
{
list.RemoveAt(i);
}
}
}
/// <summary>
/// Inserts an Item into a list at the first place that the <paramref name="predicate"/> expression fails. If it is true in all cases, then the item is appended to the end of the list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="obj"></param>
/// <param name="predicate">The sepcified function that determines when the <paramref name="obj"/> should be added. </param>
public static void InsertWhere<T>(this IList<T> list, T obj, Func<T, bool> predicate)
{
for (int i = 0; i < list.Count; i++)
{
// When the function first fails it inserts the obj paramiter.
// For example, in a list myList of ordered Int32's {1,2,3,4,5,10,12}
// Calling myList.InsertWhere( 8, x => 8 > x) inserts 8 once the list item becomes greater then or equal to it.
if(!predicate(list[i]))
{
list.Insert(i, obj);
return;
}
}
list.Add(obj);
}
Edit:
Talljoe made some significant improvements to the RemoveWhere/RemoveAll, that I had hastily constructed. With ~3mill items removing every third one the new version takes only ~50 milliseconds (less then 10 if it can call List.RemoveAll !) as opposed to the RemoveWhere 's multiple seconds (I got tired of waiting for it.)
Here is his greatly improved version, thanks again!
public static void RemoveAll<T>(this IList<T> instance, Predicate<T> predicate)
{
if (instance == null)
throw new ArgumentNullException("instance");
if (predicate == null)
throw new ArgumentNullException("predicate");
if (instance is T[])
throw new NotSupportedException();
var list = instance as List<T>;
if (list != null)
{
list.RemoveAll(predicate);
return;
}
int writeIndex = 0;
for (int readIndex = 0; readIndex < instance.Count; readIndex++)
{
var item = instance[readIndex];
if (predicate(item)) continue;
if (readIndex != writeIndex)
{
instance[writeIndex] = item;
}
++writeIndex;
}
if (writeIndex != instance.Count)
{
for (int deleteIndex = instance.Count - 1; deleteIndex >= writeIndex; --deleteIndex)
{
instance.RemoveAt(deleteIndex);
}
}
}