ThinkGeo.com    |     Documentation    |     Premium Support

Using FeatureIDsToExclude

Hi,

I thought it might be worth sharing something I found as (a) it might be helpful and (b) you might spot a problem with the method.

Essentially in our overridden variants of GetAlllFeaturesCore and GetFeaturesInBoundingBoxCore we added some code to handle excluded IDs and this made a significant performance improvement when excluding larger numbers of IDs. If we didn’t do this they were still excluded but it took much longer to draw the map.

CODE: SNIPPIT

`            if (this.FeatureIdsToExclude.Count > 0)  {
                 List<string> wanted = features.Select(
                     x => x.Id).ToList().Except(this.FeatureIdsToExclude).ToList();
                 return new Collection<Feature>(features.Where(x => wanted.Contains(x.Id)).ToList());
           }`

A quick extra note: The above was broadly correct but not totally so, as it worked well when the number to exclude was a large proportion of the total number but very inefficiently when reversed. I did some rework to create a custom Comparer for the Exclude that also simplified it a bit.

Hi Jonathan,

Thanks for your suggestion! I logged it down and we will apply your suggestion to the future versions.

Also, I think we can make a couple improvements upon your code, please have a look see if it make sense:

        if (this.FeatureIdsToExclude.Count > 0)
        {
            // avoid using ToList(), to
            // 1, avoid creating Lists to save some memory
            // 2, delay the enumerating to the foreach statement where it is really needed. 
            var wantedEnumerable = features.Select(x => x.Id).Except(this.FeatureIdsToExclude);

            // use HashSet which has O(1) for Contains, instead of List<string) which has O(n) for Contains
            var wanted = new HashSet<string>();
            foreach (var feature in wantedEnumerable)
                wanted.Add(feature);
            return new Collection<Feature>(features.Where(x => wanted.Contains(x.Id)).ToList());
        }

Also, just let you know the latest product release v13.2.* is now available on nuget. Please upgrade to that version if you are on beta.

Thanks,
Ben

Thanks Ben, that was very helpful. Prior to that I had done some rework and ended up with something a bit different again:

The bit to process the list/collection is split out and looks like this:

    // Use FeatureIDsToExclude to strip out unwanted features from the return
    private Collection<Feature> AllowForExclusions(Collection<Feature> features)
    {
        var filteredApps = features.Except(FeatureIdsToExclude.Select(x => new Feature { Id = x }), new FeatureComparer());
        return new Collection<Feature>(filteredApps.ToList());
    }

And then had this as the comparer:

/// <summary>
/// Class to manage comparing Fetaures on the bases that if the IDs are equal than they are the same feature.
/// </summary>
/// <remarks>
/// Will be used by LINQ .Except operator to manage excluding unwanted features based on a list of IDs
/// </remarks>
class FeatureComparer : IEqualityComparer<Feature>
{
    /// <summary>
    /// Straight forward string compare on IDs
    /// </summary>
    /// <param name="f1"></param>
    /// <param name="f2"></param>
    /// <returns></returns>
    public bool Equals(Feature f1, Feature f2)
    {
        return string.Equals(f1.Id, f2.Id);
    }

    /// <summary>
    /// Returns hash code of just the ID, needed by LINQ .Exclude
    /// </summary>
    /// <param name="f"></param>
    /// <returns></returns>
    public int GetHashCode(Feature f)
    {
        return f.Id.GetHashCode();
    }    }

I’ve never used IEqualityComparer before, thanks for sharing, Jonathan!