C#之LINQ中常用的ToLookup,GroupBy, Join之用法总结

一、ToLookup

Lookup<TKey,TElement> 类

     ToLookup方法是LINQ常用的扩展方法,有4个重载版本如下


            重载1:ILookup<TKey,TElement> ToLookup<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
            重载2:ILookup<TKey,TElement> ToLookup<TSource,TKey>(this IEnumerable<TSource> source, Func<TSource,TKey> keySelector)
            重载3:ILookup<TKey,TElement> ToLookup<TSource,TKey>(this IEnumerable<TSource> source, Func<TSource,TKey> keySelector, IEqualityComparer<TKey> comparer)
            重载4:ILookup<TKey,TElement> ToLookup<TSource,TKey,TElement>(this IEnumerable<TSource> source, Func<TSource,TKey> keySelector, Func<TSource,TElement> elementSelector, IEqualityComparer<TKey> comparer)
 

  class Student
    {
        public string Name;
        public double Weight;
        public int Age;
    }
    class Program
    {
        static void Main(string[] args)
        {
            LookupExample();
        }
        public static void LookupExample()
        {

            List<Student> students = new List<Student> { new Student { Name = "张三", Weight = 55.2, Age = 17 },
                                                 new Student { Name = "李三", Weight = 78.7, Age =18 },
                                                 new Student { Name = "刘三", Weight = 64.0, Age = 19 },
                                                 new Student { Name = "周元", Weight = 59.3, Age = 17 },
                                                 new Student { Name = "张大", Weight = 73.8, Age = 18 } };


            //ToLookup是LINQ常用的扩展方法,有4个重载版本如下
            //重载1:ILookup<TKey,TElement> ToLookup<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
            //重载2:ILookup<TKey,TElement> ToLookup<TSource,TKey>(this IEnumerable<TSource> source, Func<TSource,TKey> keySelector)
            //重载3:ILookup<TKey,TElement> ToLookup<TSource,TKey>(this IEnumerable<TSource> source, Func<TSource,TKey> keySelector, IEqualityComparer<TKey> comparer)
            //重载4:ILookup<TKey,TElement> ToLookup<TSource,TKey,TElement>(this IEnumerable<TSource> source, Func<TSource,TKey> keySelector, Func<TSource,TElement> elementSelector, IEqualityComparer<TKey> comparer)
            Lookup<int, string> lookup =(Lookup<int, string>)students.ToLookup(p => p.Age,
                                                            p => p.Name + ",体重=" + p.Weight+"kg,年龄="+p.Age+"岁");

            //使用IGrouping<int, string> 作为循环元素的类型,因为Lookup<TKey,TElement>类实现了IEnumerable<IGrouping<TKey,TElement>>接口
            foreach (IGrouping<int, string> packageGroup in lookup)
            {

                Console.WriteLine(packageGroup.Key);
                //使用string作为循环元素的类型,因为IGrouping<TKey,TElement> 接口继承于IEnumerable<TElement>接口
                foreach (string str in packageGroup)
                    Console.WriteLine("    {0}", str);
            }

         
            int count = lookup.Count;

            IEnumerable<string> cgroup = lookup[17];

        
            Console.WriteLine("\n年龄为17岁的学生:");
            foreach (string str in cgroup)
                Console.WriteLine(str);
            bool hasG = lookup.Contains(17);
            Console.Read();
        }

    }

二、GroupBy

     GroupBy的作用是对数据进行分组,分组后的每个对象元素是继承于IGrouping<TKey,TElement> 接口的分组对象。

 class Student
    {
        public string Name;
        public double Weight;
        public int Age;
        public override string ToString()
        {
            return $"姓名={Name},体重={Weight}Kg,年龄={Age}岁";
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            LookupExample();
        }
        public static void LookupExample()
        {

            List<Student> students = new List<Student> { new Student { Name = "张三", Weight = 55.2, Age = 17 },
                                                 new Student { Name = "李三", Weight = 78.7, Age =18 },
                                                 new Student { Name = "刘三", Weight = 64.0, Age = 19 },
                                                 new Student { Name = "周元", Weight = 59.3, Age = 17 },
                                                 new Student { Name = "张大", Weight = 73.8, Age = 18 } };

            IEnumerable<IGrouping<int, Student>> groups = students.GroupBy(g => g.Age);

//以下语句会得到同样的结果       
//     IEnumerable<IGrouping<int, Student>> groups =from stu in  students Group stu By stu.Age;


            foreach(IGrouping<int,Student> g in groups)
            {
                Console.WriteLine("Key=" + g.Key);
                //由于IGrouping<TKey,TElement>从IEnumerable<TElement>继承而来,所以下面foreach中可以使用foreach(Student stu in g)
                foreach (Student stu in g)
                {
                    Console.WriteLine(stu.ToString());
                }
            }
 
            Console.Read();
        }

    }

 

GroupBy也存在多个重载,其中常用的一个重载如下:

public static IEnumerable<IGrouping<TKey,TElement>> GroupBy<TSource,TKey,TElement> (this IEnumerable<TSource> source, Func<TSource,TKey> keySelector, Func<TSource,TElement> elementSelector);

使用该重载,则上述例子可以改为如下表示:

  IEnumerable<IGrouping<int, string>> groups = students.GroupBy(r => r.Age, r => r.Name);

            foreach(IGrouping<int,string> g in groups)
            {
                Console.WriteLine("Key=" + g.Key);
                //由于IGrouping<TKey,TElement>从IEnumerable<TElement>继承而来,所以下面foreach中可以使用foreach(string stuStr in g)
                foreach (string stuStr in g)
                {
                    Console.WriteLine(stuStr);
                }
            }

三、Join

     Join方法同样是位于Enumerable类中,是实现IEnumerable<T>接口的所有实现类的扩展方法,具有两个重载:

重载1:public static IEnumerable<TResult> Join<TOuter,TInner,TKey,TResult> (this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter,TKey> outerKeySelector, Func<TInner,TKey> innerKeySelector, Func<TOuter,TInner,TResult> resultSelector);

重载2:public static IEnumerable<TResult> Join<TOuter,TInner,TKey,TResult> (this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter,TKey> outerKeySelector, Func<TInner,TKey> innerKeySelector, Func<TOuter,TInner,TResult> resultSelector, IEqualityComparer<TKey> comparer);

类型参数

TOuter

第一个序列中的元素的类型。

TInner

第二个序列中的元素的类型。

TKey

键选择器函数返回的键的类型。

TResult

结果元素的类型。

参数

outer

IEnumerable<TOuter>

要联接的第一个序列。

inner

IEnumerable<TInner>

要与第一个序列联接的序列。

outerKeySelector

Func<TOuter,TKey>

用于从第一个序列的每个元素提取联接键的函数。

innerKeySelector

Func<TInner,TKey>

用于从第二个序列的每个元素提取联接键的函数。

resultSelector

Func<TOuter,TInner,TResult>

用于从两个匹配元素创建结果元素的函数。

comparer

IEqualityComparer<TKey>

用于对键进行哈希处理和比较的 IEqualityComparer<T>

返回

IEnumerable<TResult>

一个 IEnumerable<T>,其中包含通过对两个序列执行内部联接获得的、类型为 TResult 的元素。

此方法是使用延迟执行实现的。 即时返回值是一个对象,该对象存储执行操作所需的所有信息。 此方法表示的查询在枚举对象之前不会执行,方法是直接调用其 GetEnumerator 方法,或者通过 foreach 在 Visual c # 中使用或 For Each 在 Visual Basic 中使用。

class Person
{
    public string Name { get; set; }
}

class Pet
{
    public string Name { get; set; }
    public Person Owner { get; set; }
}

public static void JoinEx1()
{
    Person magnus = new Person { Name = "Hedlund, Magnus" };
    Person terry = new Person { Name = "Adams, Terry" };
    Person charlotte = new Person { Name = "Weiss, Charlotte" };

    Pet barley = new Pet { Name = "Barley", Owner = terry };
    Pet boots = new Pet { Name = "Boots", Owner = terry };
    Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
    Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

    List<Person> people = new List<Person> { magnus, terry, charlotte };
    List<Pet> pets = new List<Pet> { barley, boots, whiskers, daisy };

    // Create a list of Person-Pet pairs where
    // each element is an anonymous type that contains a
    // Pet's name and the name of the Person that owns the Pet.
    var query =
        people.Join(pets,
                    person => person,
                    pet => pet.Owner,
                    (person, pet) =>
                        new { OwnerName = person.Name, Pet = pet.Name });

    foreach (var obj in query)
    {
        Console.WriteLine(
            "{0} - {1}",
            obj.OwnerName,
            obj.Pet);
    }
}

关于Join,又有内连接,左外连接,组连接等方式,可以参考官方文档join clause (C# Reference)

 

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页