LINQ-SelectMany用法

聲明:本文爲www.cnc6.cn原創

一、第一種用法:

public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector);

官方釋義:將序列的每個元素投影到 IEnumerable<TResult> 並將結果序列合併爲一個序列。

廢話不多說,直接Post上代碼:

1,編寫Person類:

複製代碼

    class Person
    {
        public string Name { set; get; }
        public int Age { set; get; }
        public string Gender { set; get; }
        public Dog[] Dogs { set; get; }
    }

複製代碼

2,編寫Dog類:

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

請注意:在Person類裏有一個Dog數組,用於存儲實例化Person類所擁有的所有Dog集合,這裏就是SelectMany的關鍵。

3、編寫客戶端試驗代碼:

複製代碼

            List<Person> personList = new List<Person>
            {
                new Person
                {
                    Name = "P1", Age = 18, Gender = "Male",
                    Gogs = new Dog[]
                    {
                        new Dog { Name = "D1" },
                        new Dog { Name = "D2" }
                    }
                },
                new Person
                {
                    Name = "P2", Age = 19, Gender = "Male",
                    Gogs = new Dog[]
                    {
                        new Dog { Name = "D3" }
                    }
                },
                new Person
                {
                    Name = "P3", Age = 17,Gender = "Female",
                    Dogs = new Dog[]
                    {
                        new Dog { Name = "D4" },
                        new Dog { Name = "D5" },
                        new Dog { Name = "D6" }
                    }
                }
            };
            var dogs = personList.SelectMany(p => p.Dogs);
            foreach (var dog in dogs)
            {
                Console.WriteLine(dog.Name);
            }

複製代碼

在這裏我們定義了由Person構成的List列表,並使用集合及對象初始化器初始化了一些數據。

在這裏,SelectMany的作用就是:將personList集合對象的每個元素(每個Person實例對象,如名爲“P1”,“P2”,“P3”)

映射到每個Person類對應的Dog集合(如名爲“P1”對應Dog名爲D1及D2的Dog集合),

並將每個Person類對應Dog的集合重新組合成一個大的Dog集合。

因此,以上將會輸出以下結果:

實際以上的SelectMany對應的LINQ語句爲:

 var dogs = from p in personList
            from d in p.Dogs
            select d;

我們可以將其代替試試就知道結果。

2、第二種用法:

public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TResult>> selector);

官方釋義:將序列的每個元素投影到 IEnumerable<TResult>,並將結果序列合併爲一個序列。每個源元素的索引用於該元素的投影表。

其實,就是比第一種使用方法多一個索引而已,該索引是從0開始,針對的是TSource指定類型的集合,最大索引值爲TSource個數-1。

我們將第一種客戶端試驗代碼中的

 var dogs = personList.SelectMany(p => p.Dogs);

修改爲

var dogs = personList.SelectMany((p, i) => 
    p.Dogs.Select( d=>
    {
        d.Name = $"{i},{d.Name}";
        return d;
    }));

以上方法僅僅是把索引值加到Dog類的Name屬性上。

由以上可以看到,共有3個Person,因此,索引值最大爲2,每個Person類有多少個Dog(如名爲P1的Person類,共有2個Dog),

對應的索引就被使用了多少次數(如名爲P1的Person類,索引0被使用了2次),

輸出結果如下:

三、第三種用法:

public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector);

官方釋義:將序列的每個元素投影到 IEnumerable<TCollection>,並將結果序列合併爲一個序列,並對其中每個元素調用結果選擇器函數。

這個用法,跟第一種用法相比,就是可以對已合成一個大集合的每個元素調用結果選擇器,返回自己想要的集合類型。

編寫客戶端試驗代碼:

複製代碼

            List<Person> personList = new List<Person>
            {
                new Person
                {
                    Name = "P1", Age = 18, Gender = "Male",
                    Gogs = new Dog[]
                    {
                        new Dog { Name = "D1" },
                        new Dog { Name = "D2" }
                    }
                },
                new Person
                {
                    Name = "P2", Age = 19, Gender = "Male",
                    Gogs = new Dog[]
                    {
                        new Dog { Name = "D3" }
                    }
                },
                new Person
                {
                    Name = "P3", Age = 17,Gender = "Female",
                    Gogs = new Dog[]
                    {
                        new Dog { Name = "D4" },
                        new Dog { Name = "D5" },
                        new Dog { Name = "D6" }
                    }
                }
            };
            var results = personList.SelectMany(p => p.Dogs, (p, d) => new { PersonName = p.Name, DogName = d.Name });
            foreach (var result in results)
            {
                Console.WriteLine($"{result.PersonName},{result.DogName}");
            }

複製代碼

關於SelectMany的用法說明如下:

第一個參數:p=>p.Dogs,p指定是想要處理的每個Person對象,而p.Dogs則是想讓p實例映射的Dog集合;

第二個參數:(p, d) => new { PersonName = p.Name, DogName = d.Name },p與d分別指定是映射後(其實有點類似數據庫的CROSS JOIN)的person實例與dog實例,

如名爲P1的Person類,其Dogs名爲D1及D2,那麼p與d就是:P1/D1,P1/D2(指定是名稱),處理其他Person類也是如此。而new { PersonName = p.Name, DogName = d.Name }則是返回的一個由自己定義的匿名類型。

結果輸出如下:

實際以上的SelectMany對應的LINQ語句爲:

var results = from p in personList
              from d in p.Dogs
              select new { PersonName = p.Name, DogName = d.Name };

四、第四種用法:

public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector);

官方釋義:將序列的每個元素投影到 IEnumerable<TCollection>,並將結果序列合併爲一個序列,並對其中每個元素調用結果選擇器函數。每個源元素的索引用於該元素的中間投影表。

其實,就是比第三種使用方法多一個索引而已,該索引是從0開始,針對的是TSource指定類型的集合,最大索引值爲TSource個數-1。

我們將第三種客戶端試驗代碼中的

var results = personList.SelectMany(p => p.Dogs, (p, d) => new { PersonName = p.Name, DogName = d.Name });

修改爲

複製代碼

var results = personList.SelectMany((p,i) =>
{
    for(int j=0;j<p.Dogs.Length;j++)
    {
        p.Dogs[j].Name = $"{i}-{p.Dogs[j].Name}";
    }
    return p.Dogs;
}, (p, d) => new { PersonName = p.Name, DogName = d.Name });

複製代碼

以上方法僅僅是把索引值加到Dog類的Name屬性上,並將Dog集合返回。

由以上可以看到,共有3個Person,因此,索引值最大爲2,每個Person類有多少個Dog(如名爲P1的Person類,共有2個Dog),

對應的索引就被使用了多少次數(如名爲P1的Person類,索引0被使用了2次),

輸出結果如下:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章