cfly24
cfly24

Reputation: 1962

Trouble when using C# .Distinct()

I am trying to fill a dropdown with a list of regions that come from a database. The regions are coming from a table where there can be many rows with the same region, so I am using .Distinct() to display only 1 of each in the dropdown. Lets say there are 100 NORTHWEST's in the database. I am using .Distinct() to group them all together so just one NORTHWEST is displayed in the dropdown.

I added the ability to disable and enable regions, which I don't want to affect how they are viewed in the dropdown, but is used for other functionality. The user has the ability to disable or enable any of the 100 in the model (may not make sense, but it has its purpose). They are enabled and disabled with a bit value in the database. The issue comes if there is at least one NORTHWEST enabled and one disabled. Then what I am calling RegionState has a true value and a false value meaning that it displays twice in the dropdown because they are distinct from eachother.

var context = new TestContext();
var viewModel = new TestViewModel();

viewModel.Regions = context.Select(r => new Region 
   { Name = r.Region, 
     RegionState = r.RegionState 
   }).Distinct().OrderBy(r => r.Name);

ViewModel:

    public class TestViewModel
    {
    public IEnumerable<Region> Regions;
    }

Model:

    public class Region
    {
    public String Name;
    public bool RegionState { get; set; }
    }

How could I use .Distinct() to only filter based on the name, while allowing regions with both a true and false RegionState to appear as one in the dropdown. I need to keep RegionState in the viewmodel.

Let me know if you have any questions. May be a bit confusing.Thanks!

Upvotes: 0

Views: 292

Answers (2)

Eser
Eser

Reputation: 12546

How could I use .Distinct() to only filter based on the name, while allowing regions with both a true and false RegionState to appear as one in the dropdown

EDIT As noted by @juharr, below methods wouldn't work with entity framework, Better replace your .Distinct() with .GroupBy(r=>r.Name).Select(g=>g.First())


Implement IEqualityComparer<Region> and call Distinct() as Distinct(new RegionComparer())

public class RegionComparer : IEqualityComparer<Region>
{
    public bool Equals(Region x, Region y)
    {
        return x.Name == y.Name;
    }

    public int GetHashCode(Region obj)
    {
        return obj.Name.GetHashCode();
    }
}

You can also write a custom DistinctBy extension method

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector)
{
    var items = new HashSet<TKey>();
    return source.Where(x => items.Add(selector(x)));
}

Then you can use it as .DistinctBy(region=>region.Name)

Upvotes: 0

William Barbosa
William Barbosa

Reputation: 5005

Filter it before applying distinct using Where

viewModel.Regions = context.Where(r => r.PropertyThatIndicatesItIsEnabled)
                           .Select(r => new Region { Name = r.Region, RegionState = r.RegionState })
                           .Distinct()
                           .OrderBy(r => r.Name)

Upvotes: 1

Related Questions