如何使用 LINQ 从多个列表中找到 Distinct?

How to find Distinc from the multiple lists using LINQ?

我需要从整个国家集合中找到所有不同的项目(宗教),其中每个国家都有自己的项目(宗教)列表。这是我的对象 class:

public class Country
    {        
        public string Name { get; }
        public List<string> Religions { get; }

        public Country(string name, List<string> religions)
        {
             Name = name;
             Religions = religions;
        }

        public static List<Country> GetCountries()
        {
             return new List<Country>()
             {
                  new Country( "Venezuela", new List<string> { "Roman Catholic", "Protestant" } ),
                  new Country( "Peru", new List<string> { "Roman Catholic", "Evangelical" } ),
                  new Country( "Paraguay", new List<string> { "Roman Catholic", "Protestant" } ),
                  new Country( "Bolivia", new List<string> { "Roman Catholic", "Evangelical", "Protestant" } )
             };  
        }
       
        public override string ToString() =>
                  $"\n{Name} \nReligions: {string.Join(", ", Religions)}";
     }  

这是我的主要内容 class:

List<Country> countries = Country.GetCountries();

AllReligions(countries);

Console.ReadKey();

static void AllReligions(List<Country> countries) 
{
     var distinctReligions = countries
         .Select(r => new { r.Religions })
         .Distinct()
         .ToList();

     Console.WriteLine("Religions in South America:");
         foreach (var rel in distinctReligions)                
             Console.WriteLine(rel);
}

我正在对代码进行第 5 次迭代,其中一个问题是我不知道错误发生在何处 - 在我的 DISTINCT 函数内或在我的打印输出函数内。任何帮助将不胜感激。这是打印输出:

两者都错了。两者都适用于匿名对象,而不适用于宗教字符串。

要获得不同的宗教,您需要使用 SelectMany 来“扁平化”country/religion 图表:

IEnumerable<string> religions=Country
                             .GetCountries()
                             .SelectMany(country=>country.Religions)
                             .Distinct();

Console.WriteLine("Religions in South America:");

foreach (var rel in religions)   
{             
    Console.WriteLine(rel);
}

查询形式的等价物是:

var religions = ( from country in Country.GetCountries()
                  from religion in country.Religions
                  select religion
                ).Distinct();

你这里有几个问题。

  1. 您认为使用 .Select(r => new { r.Religions }) 得到的结果 - 它为您提供列表列表。您想要的是 SelectMany(r => r.Religions) - 这样,您将获得宗教列表,而不是在其 属性.

    中包含列表的匿名对象列表
  2. Distinct使用基本比较,需要自己写自定义比较器提供重载:

Distinct<TSource>(IEnumerable<TSource>, IEqualityComparer<TSource>)

您需要实施 IEqualityComparer<Religion>

更新:宗教只是一个字符串,所以你不需要实现一个,在使用 SelectMany 之后一切都应该很好。

  1. 你的“打印输出”功能 - 你使用 Console.WriteLine 只调用对象上的 ToString - 因为你有列表,它看起来很奇怪 :) 在建议使用 SelectMany 之后应该离开。