代码之家  ›  专栏  ›  技术社区  ›  Ali Tarhini

使用SelectMany()的不同方法

  •  13
  • Ali Tarhini  · 技术社区  · 14 年前

    我想知道如何使用 SelectMany() . 似乎需要这么多的争论,从我自己的角度来看,我注意到 selectmany 可能是所有其他选择操作的“父”。

    6 回复  |  直到 5 年前
        1
  •  31
  •   Graham francescalus    7 年前

    Select many允许您从查询源中选择一个属于IEnumerable<T>集合的属性,但它不会返回集合(IEnumerable<IEnumerable<T>)而是将集合展平为单个集合。

    下面是一个示例,您可以运行它来演示Select和SelectMany之间的区别:

    //set up some data for our example
    var tuple1 = new { Name = "Tuple1", Values = new int [] { 1, 2, 3 } };
    var tuple2 = new { Name = "Tuple2", Values = new int [] { 4, 5, 6 } };
    var tuple3 = new { Name = "Tuple3", Values = new int [] { 7, 8, 9 } };
    
    //put the tuples into a collection
    var tuples = new [] { tuple1, tuple2, tuple3 };
    
    //"tupleValues" is an IEnumerable<IEnumerable<int>> that contains { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }
    var tupleValues = tuples.Select(t => t.Values);
    
    //"tupleSelectManyValues" is an IEnumerable<int> that contains { 1, 2, 3, 4, 5, 6, 7, 8, 9 }
    var tupleSelectManyValues = tuples.SelectMany(t => t.Values);
    

    通过使用SelectMany,可以更轻松地查询子集合中的值。

        2
  •  13
  •   roland    7 年前

    有几个重载 SelectMany . 其中一个允许您在遍历层次结构时跟踪父级和子级之间的任何关系。

    例子 :假设您有以下结构: League -> Teams -> Player

    你可以很容易地返回一个单位的球员集合。不过,你可能会失去对球员所属球队的任何参考。

    幸运的是,有一个超载的目的:

    var teamsAndTheirLeagues = 
             from helper in leagues.SelectMany
                   ( l => l.Teams
                     , ( league, team ) => new { league, team } )
                          where helper.team.Players.Count > 2 
                               && helper.league.Teams.Count < 10
                               select new 
                                      { LeagueID = helper.league.ID
                                        , Team = helper.team 
                                       };
    

    上一个例子取自丹的IK博客:

    http://blogs.interknowlogy.com/2008/10/10/use-linqs-selectmany-method-to-flatten-collections/

    强烈地 建议你看看。

        3
  •  6
  •   Dean Chalk    14 年前

    SelectMany基本上是扁平化和处理分层数据,它有两种主要形式

    (为了示例的目的,请参阅此初始代码)

    class TestObj
    {
        public string Name { get; set; }
        public List<string> Items { get; set; }
    }
    
    var hierarchicalCollection = new List<TestObj>();
    
    hierarchicalCollection.Add(new TestObj() 
        {Items = new List<string>()
            {"testObj1-Item1", "testObj1-Item2"}, Name="t1"});
    hierarchicalCollection.Add(new TestObj() 
        {Items = new List<string>()
            {"testObj2-Item1", "testObj2-Item2"}, Name="t2"});
    

    选项1)从集合中创建集合(基本上是展开分层数据)

    IEnumerable<string> flattenedCollection = 
        hierarchicalCollection.SelectMany(t => t.Items);
    

    结果是:

    "testObj1-Item1"
    "testObj1-Item2"
    "testObj2-Item1"
    "testObj2-Item2"
    

    选项2)从集合创建集合,然后通过对原始父集合的引用处理新集合的每个项

    IEnumerable<string> flattenedModifiedCollection = 
        hierarchicalCollection.SelectMany
            (t => t.Items, (t, i) => t.Name + " : " + i);
    

    结果是:

    "t1 : testObj1-Item1"
    "t1 : testObj1-Item2"
    "t2 : testObj2-Item1"
    "t2 : testObj2-Item2"
    

    上面的每个用法都有一个变体,在这个变体中,转换函数可以使用正在处理的项的索引。

        4
  •  3
  •   Tom    14 年前

    我用这个分机 全部的 进入等级制度的时间。

    当扩展变得有点混乱时,另一个很酷的方法是使用正式的LINQ方法,比如:

    var vehicles = from cust in context.Customers
                   from fleet in cust.Fleets
                   from v in fleet.Vehicles
                   select v;
    

    这相当于:

    var vehicles = context.Customers.SelectMany(c => c.Fleets).SelectMany(f => f.Vehicles);
    

    当添加where子句和连接等时,这可能会有点冗长。 希望这有帮助!

        5
  •  0
  •   Aussie Craig    14 年前

    我在LINQ中使用SelectMany获得了一些乐趣。下面的链接描述了在返回序列序列的LINQ select子句中返回一个IEnumerable,并使用SelectMany将其展平为一个简单序列。 "Linq to XML using Let, Yield return and Selectmany" . 它不仅仅是一个SelectMany用例,而是从LINQ中的单个输入生成多个输出的方法的一部分。

        6
  •  0
  •   d219    6 年前

    下面是另一个(VB.NET)使用示例:

    'Original list
    Dim l() As String = {"/d", "/bc:\Temp\In*;c:\Temp\Out", "/hABC", "/s123"}
    
    'Processed list: will list first 2 characters from each string member.
    Dim L1 As IEnumerable(Of String) = l.SelectMany(Function(x As String) {x.Substring(0, 2)})
    
    Dim L2 As List(Of String) = l.SelectMany(Function(x As String) {x.Substring(0, 2)}).ToList
    
    'Will return dictionary like list with keys==2 characters and values the rest from each string member.
    Dim L3 As List(Of KeyValuePair(Of String, String)) = l.SelectMany(Function(x As String) {New KeyValuePair(Of String, String)(x.Substring(0, 2), x.Substring(2))}).ToList