Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find And Remove Items From Collection

Tags:

c#

linq

What is the best way to remove a set from a collection, but still keep the items that were removed in a separate collection?

I have written an extension method that does that, but I think there must be a better way. Here is my function:

public static List<T> FindAndRemove<T>(this List<T> lst, Predicate<T> match)
{
    List<T> ret = lst.FindAll(match);
    lst.RemoveAll(match);
    return ret;
}

And you would use it like this:

List<String> myList = new List<String>();
myList.Add("ABC");
myList.Add("DEF");
myList.Add("ABC");
List<String> removed = myList.FindAndRemove(x => x == "ABC");
// myList now contains 1 item (DEF)
// removed now contains 2 items (ABC, ABC)

I'm not 100% sure what goes on behind the scenes in the FindAll and RemoveAll methods, but I imagine a better way would be to somehow "transfer" items from one list to the other.

like image 378
Eric Avatar asked Mar 05 '12 15:03

Eric


People also ask

How do I remove an object from a Collection in Java?

remove() method is used to remove elements from a collection. It removes the element at the specified position in this list. Shifts any subsequent elements to the left by subtracts one from their indices.

How do I remove all objects from a list?

The Java ArrayList removeAll() method removes all the elements from the arraylist that are also present in the specified collection. The syntax of the removeAll() method is: arraylist. removeAll(Collection c);


1 Answers

Op's answer is the best out of the proposed and suggested solutions so far. Here are timings on my machine:

public static class Class1
{
    // 21ms on my machine
    public static List<T> FindAndRemove<T>(this List<T> lst, Predicate<T> match)
    {
        List<T> ret = lst.FindAll(match);
        lst.RemoveAll(match);
        return ret;
    }

    // 538ms on my machine
    public static List<T> MimoAnswer<T>(this List<T> lst, Predicate<T> match)
    {
        var ret = new List<T>();
        int i = 0;
        while (i < lst.Count)
        {
            T t = lst[i];
            if (!match(t))
            {
                i++;
            }
            else
            {
                lst.RemoveAt(i);
                ret.Add(t);
            }
        }
        return ret;
    }

    // 40ms on my machine
    public static IEnumerable<T> GuvanteSuggestion<T>(this IList<T> list, Func<T, bool> predicate)
    {
        var removals = new List<Action>();

        foreach (T item in list.Where(predicate))
        {
            T copy = item;
            yield return copy;
            removals.Add(() => list.Remove(copy));
        }

        // this hides the cost of processing though the work is still expensive
        Task.Factory.StartNew(() => Parallel.ForEach(removals, remove => remove()));
    }
}

[TestFixture]
public class Tester : PerformanceTester
{
    [Test]
    public void Test()
    {
        List<int> ints = Enumerable.Range(1, 100000).ToList();
        IEnumerable<int> enumerable = ints.GuvanteSuggestion(i => i % 2 == 0);
        Assert.That(enumerable.Count(), Is.EqualTo(50000));
    }
}
like image 160
David Peden Avatar answered Oct 06 '22 00:10

David Peden