欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

[C#] LINQ之SelectMany

程序员文章站 2022-08-27 12:13:41
声明:本文为www.cnc6.cn原创,转载时请注明出处,谢谢! 一、第一种用法: 官方释义:将序列的每个元素投影到 IEnumerable 并将结果序列合并为一个序列。 废话不多说,直接Post上代码: 1,编写Person类: 2,编写Dog类: 请注意:在Person类里有一 ......

声明:本文为原创,转载时请注明出处,谢谢!

一、第一种用法:

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集合。

因此,以上将会输出以下结果:

[C#] LINQ之SelectMany

实际以上的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次),

输出结果如下:

[C#] LINQ之SelectMany

三、第三种用法:

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 }则是返回的一个由自己定义的匿名类型。

结果输出如下:

[C#] LINQ之SelectMany

实际以上的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次),

输出结果如下:

[C#] LINQ之SelectMany