Splitting two ObservableCollections lightning fast I'm working on wiring up a bindable Map for Xamarin Forms, and I need a fast way of dividing up the ObservableCollections (collection of map markers) as quickly as possible. Collections are a weak area for me, and I find myself doing too many foreach's when they're not necessary.

Here's what I have now.

private static void MarkerSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    var markers = ((IEnumerable&lt;XfxMarker&gt;) sender).ToList();

    var comparer = new MapMarkerComparer();
    var offScreen = new List&lt;XfxMarker&gt;();
    var markersToAdd = markers.Where(m =&gt; _map.MapBounds.Contains(m.CenterPoint), out offScreen)
        .Except(_oldMarkers, comparer);

    var markersToRemove = _oldMarkers.Except(markers, comparer).Union(offScreen);
    _map.HandleMarkersChanged(markers, new MapMarkersChangedEventArgs(markersToAdd, markersToRemove));
    _oldMarkers = markers;
}


With the comparer

internal class MapMarkerComparer : IEqualityComparer&lt;XfxMarker&gt;
{
    public bool Equals(XfxMarker x, XfxMarker y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) return false;
        var result = x.CenterPoint.Latitude.ToString() == y.CenterPoint.Latitude.ToString()
                     &amp;&amp; x.CenterPoint.Longitude.ToString() == y.CenterPoint.Longitude.ToString();
        return result;
    }

    public int GetHashCode(XfxMarker obj)
    {
        unchecked
        {
            var hash = 0;
            if (obj.CenterPoint == null) return hash;
            hash = hash + 17;
            hash = hash*23 + obj.CenterPoint.Longitude.GetHashCode();
            hash = hash*23 + obj.CenterPoint.Latitude.GetHashCode();
            return hash;
        }
    }
}


And my custom Where extension.

    public static IEnumerable&lt;T&gt; Where&lt;T&gt;(this IEnumerable&lt;T&gt; input, Func&lt;T, bool&gt; predicate, out List&lt;T&gt; remainder)
    {
        var leftover = new List&lt;T&gt;();
        var output = new List&lt;T&gt;();
        foreach (var item in input)
        {
            if (predicate.Invoke(item))
            {
                output.Add(item);
            }
            else
            {
                leftover.Add(item);
            }
        }
        remainder = leftover;
        return output;
    }
}


Now I'm sure there has to be a more efficient way to split these lists, but I'm just not sure what.
NotifyCollectionChangedEventArgs

You receive a NotifyCollectionChangedEventArgs, wich holds interesting data about the items that got added NewItems and removed OldItems from the collection. There is also an Action that defines how the collection got modified. Your changed handler is implemented as a NotifyCollectionChangedAction.Reset handler. It doesn't take into account the information from the event e. 


var markers = ((IEnumerable&lt;XfxMarker&gt;) sender).ToList();



This means, you are checking all elements against the previously cached elements by the handler container class and manually verify which ones are added and which ones removed. Let's say filter is m =&gt; _map.MapBounds.Contains(m.CenterPoint):


 var markersToAdd = markers
    .Where(m =&gt; filter(m), out offScreen).Except(_oldMarkers,comparer);



and 


var markersToRemove = _oldMarkers.Except(markers, comparer).Union(offScreen);



However, in most cases I presume the action to be Add or Remove. If this is the case, you already have the new and/or old elements. For instance, on Add:

var markersAddedInSource = e.NewItems.OfType&lt;XfxMarker&gt;();
var markersToAdd = markersAddedInSource.Where(filter);
var markersToRemove = markersAddedInSource.Except(markersToAdd);


Or using your own extension method:

var markersAddedInSource = e.NewItems.OfType&lt;XfxMarker&gt;();
var markersToAdd = markersAddedInSource.Where(filter, out var markersToRemove);


This saves you a couple of iterations on the source collection and allows you to only iterate on the changed elements.



MapMarkerComparer

I don't know the type of Latitude and Longitude, but consider checking equality on their source type rather than their ToString outcome. 


x.CenterPoint.Latitude.ToString() == y.CenterPoint.Latitude.ToString()



In case you have issues with rounding or truncation (likely with float or double) you could round the values in the check.

x.CenterPoint.Latitude == y.CenterPoint.Latitude


Or you could use rounding:

Math.Round(x.CenterPoint.Latitude, precision) 
    == Math.Round(y.CenterPoint.Latitude, precision)


Or you could guard against a tolerance threshold:

Math.Abs(x.CenterPoint.Latitude - y.CenterPoint.Latitude) &lt; tolerance




IEnumerable&lt;T&gt; Where&lt;T&gt;

Consider changing the method signature to

public static ILookup&lt;bool, T&gt; Where&lt;T&gt;(this IEnumerable&lt;T&gt; input, Func&lt;T, bool&gt; predicate);


Or returning a Dictionary:

public static IDictionary&lt;bool, IEnumerable&lt;T&gt;&gt; Where&lt;T&gt;(
    this IEnumerable&lt;T&gt; input, Func&lt;T, bool&gt; predicate);


So you don't need to worry about a return value and an out-parameter. This pattern isn't used that much anymore and is mostly used to Try* operations.

You can get the items that matched the predicate: 

var results = markers.Where(filter);
var matched = results[true];
var unmatched = results[false];


Considering renaming Where to avoid confusion with LINQ's Where method.