3

I'm working on a Silverlight 2/3 application. I would like to use List.RemoveAll (or maybe it's IList.RemoveAll?) and specify a predicate so that I can remove a bunch of elements from a list in one sweep.

It seems like this function doesn't exist in Silverlight, though. Am I missing something here? Is there an alternative approach that's equally easy? Right now, I'm manually iterating over my elements in a foreach and keeping a second list (because you can't delete while iterating), and it's quite ... cumbersome.

ashes999
  • 35
  • 1
  • 3
  • P.S. got the idea from http://stackoverflow.com/questions/308466/how-to-modify-or-delete-items-from-an-enumerable-collection-while-iterating-throu – ashes999 Jan 25 '10 at 18:10

3 Answers3

3

You can use LINQ like:

list = list.Where(predicate).ToList();

The alternative approach is to remove the elements in a for loop:

for (int i = list.Count - 1; i >= 0; --i)
    if (predicate(list[i])) 
         list.RemoveAt(i);
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • I get a compilation error similar to: System.Collections.Generic.IList' does not contain a definition for 'Where' and no extension method 'Where' ... – ashes999 Jan 25 '10 at 19:24
  • 1
    @ashes999: Make sure there's a `using System.Linq;` on top of your source file. Also, make sure `System.Core` is referenced in your project. I tested it in Silverlight 3 and it should work. – Mehrdad Afshari Jan 25 '10 at 19:31
  • Precisely the solution I wanted -- using System.Linq! – ashes999 Jan 25 '10 at 19:55
3

If what you really need is access to the subset, then there's really no reason to do the remove, just access the subset like this:

Instead of (potentially:

List<string> subSet = l.RemoveAll ( p => !p.StartsWith ("a") );

Just get the inverse:

List<string> l = new List<string> () { "a", "b", "aa", "ab" };
var subSet = l.Where ( p => p.StartsWith ( "a" ) );


OK but to really remove them (assuming the same starting list as above):
l.Where ( p => p.StartsWith ( "a" ) ).ToList ().ForEach ( q => l.Remove ( q ) );

.Where is an extension method on IEnumerable, in System.Linq. So as long as your list is a generic IEnumerable (and you've added the using) it should be available.

Bobby
  • 1,666
  • 3
  • 16
  • 27
  • This is precisely the problem; l.RemoveAll and l.Where do not exist and throw compilation errors. This is what I'm trying to resolve... And I really *do* need to remove them :) – ashes999 Jan 25 '10 at 19:22
  • those definitely do exist, the last code fragment will do it, I compiled and ran this in a Silverlight app before writing this :) – Bobby Jan 25 '10 at 19:38
  • It is annoying that they dropped the RemoveAll though, I suppose to help slim down the client Framework. – Bobby Jan 25 '10 at 19:46
  • Very useful -- close to the solution I used. But ultimately, I was trying to resolve the syntax error as to why Linq didn't work. – ashes999 Jan 25 '10 at 19:55
  • PS: you will need to pass in Func rather than Predicate to Where for silverlight. – basarat Dec 19 '10 at 05:47
2

I'm with Mehrdad on this, an extension method does the trick. To give you the full signature, here it is:

    /// <summary>
    /// Removes all entries from a target list where the predicate is true.
    /// </summary>
    /// <typeparam name="T">The type of item that must exist in the list.</typeparam>
    /// <param name="list">The list to remove entries from</param>
    /// <param name="predicate">The predicate that contains a testing criteria to determine if an entry should be removed from the list.</param>
    /// <returns>The number of records removed.</returns>
    public static int RemoveAll<T>(this IList<T> list, Predicate<T> predicate)
    {
        int returnCount = 0;

        for (int i = list.Count - 1; i >= 0; --i)
        {
            if (predicate(list[i]))
            {
                list.RemoveAt(i);
                returnCount++;
            }
        }

        return returnCount;
    }