在捕获索引时使用 LINQ 展平列表

Posted

技术标签:

【中文标题】在捕获索引时使用 LINQ 展平列表【英文标题】:Using LINQ to flatten lists while capturing the index 【发布时间】:2012-01-19 16:29:46 【问题描述】:

我有一个List<List<List<Foo>>>,我想将其展平为List<new Foo, Ndx>,其中Ndx 是最外层列表的索引。例如,如果我有类似的东西:

new List()
    new List()
        new List() new Foo("a"), new Foo("b"),
        new List() new Foo("c"),
    new List()
        new List() new Foo("x"), new Foo("y")

对于“a”、“b”和“c”,我的 Ndx 可能最终为 0,而“x”和“y”的 Ndx 为 1。有人有 LINQ 解决方案吗?

【问题讨论】:

"我有一个 List>>" ...哇,肯定有更好的结构吗? @Yuck:Yuck 只是你的名字还是你的意见? :) @StuartGolodetz 这实际上是我的名字;我的父母很残忍。 并不意味着粗鲁地顺便说一句 - 只是因为您对数据结构表示厌恶并用“- Yuck”跟进这一事实而感到震惊:) 最终结果集中应该有多少项? 【参考方案1】:

有点繁琐,但你可以这样做:

IEnumerable<Tuple<Foo,int>> result =
    tree.SelectMany(
        (L1,i) => L1.SelectMany(
            L2 => L2.Select(
                k => Tuple.Create(k,i)
            )
        )
    );

一个可编译的版本是:

using System;
using System.Collections.Generic;
using System.Linq;

class Foo

    public string s;

    public Foo(string s)
    
        this.s = s;
    


class Program

    static void Main(string[] args)
    
        var tree = new List<List<List<Foo>>>
        
            new List<List<Foo>>
            
                new List<Foo>  new Foo("a"), new Foo("b") ,
                new List<Foo>  new Foo("c") 
            ,
            new List<List<Foo>>
            
                new List<Foo>  new Foo("x"), new Foo("y") 
            
        ;

        IEnumerable<Tuple<Foo,int>> result = tree.SelectMany((L1,i) => L1.SelectMany(L2 => L2.Select(k => Tuple.Create(k,i))));
        foreach(var si in result)
        
            Console.WriteLine(si.Item1.s + ' ' + si.Item2);
        
    

编辑:正如@sll 指出的那样,由于使用了Tuple,此解决方案需要.NET 4。如有必要,适应也不会太难。

【讨论】:

@sll:很公平。我承认我一直是一名 C++ 程序员(我今年早些时候才开始使用 C#),所以我对最新的 .NET 中的新内容或新内容有些迷茫。【参考方案2】:

应该这样做:

var l = new List<List<List<Foo>>>()
            new List<List<Foo>>()
                new List<Foo>() new Foo("a"), new Foo("b"),
                new List<Foo>() new Foo("c"),
            new List<List<Foo>>()
                new List<Foo>() new Foo("x"), new Foo("y");

var q = l.SelectMany ((x, i) => 
            x.SelectMany (y => 
                y.Select (z => new  z, i )));

【讨论】:

以上是关于在捕获索引时使用 LINQ 展平列表的主要内容,如果未能解决你的问题,请参考以下文章

使用Linq获取列表中对象的索引[重复]

使用 Linq 从列表中获取所有匹配值的索引

使用 LINQ 展平列表列表以获取父/子列表

如何使用 LINQ 从列表中选择提供的索引范围内的值

在c#中使用lambda或linq查找项目索引[关闭]

将索引字段添加到LINQ列表 使用C#的结果