Get Distinct Parent Items using Lambda

2019-07-21 16:10发布

问题:

I have the following three classes;

public class City
{
    public int CityId { get; set; }
    public Region Region { get; set; }
    public string Name { get; set; }
}

public class Region
{
    public int RegionId { get; set; }
    public Country Country { get; set; }
    public string Name { get; set; }
}

public class Country
{
    public string CountryCode { get; set; }
    public string Name { get; set; }
}

I have populated a City List object to contain a number of cities, of which each have a Region and a Country.

Now I want to get a list of all countries for all cities. I've tried the following;

List<City> CityObjectList = GetAllCity();
CityObjectList.Select(r => r.Region).ToList().Select(c => c.Country).ToList();

However, all I get back is all the countries. How can I get the distinct countries ?

回答1:

You can use:

var allCityCountries = CityObjectList.Select(c => c.Region.Country).ToList();

This list is not distinct. To make the countries unique you could either override Equals + GetHashCode in Country, implement a custom IEqualityComparer<Country> for Enumerable.Disinct or use GroupBy(slowest but easiest option):

var distinctCountries = CityObjectList
    .Select(c => c.Region.Country)
    .GroupBy(c => c.CountryCode)
    .Select(g => g.First())
    .ToList();

The IEqualityComparer<T> way:

class CountryCodeComparer : IEqualityComparer<Country>
{
    public bool Equals(Country x, Country y)
    {
        if(object.ReferenceEquals(x, y)) return true;
        if(x == null || y == null) return false;
        return x.CountryCode == y.CountryCode;
    }

    public int GetHashCode(Country obj)
    {
        return obj == null ? 0 : obj.CountryCode == null ? 0 : obj.CountryCode.GetHashCode();
    }
}

Now you can use Distinct with an instance of it:

var comparer = new CountryCodeComparer();
distinctCountries = CityObjectList.Select(c => c.Region.Country).Distinct(comparer).ToList();