使用LINQ连接List<List<string>>中所有的字符串

4
我的问题和这个问题几乎相同,但是列表的维度为n。 如何使用LINQ连接所有List<List<List...<string>>(n维列表)中的所有字符串?
注意:对于已知或未知的n,都感兴趣。

使用C#对吧?因为同样的问题被标记了C#。 - M.kazem Akhgary
由于列表类型未知,您应该使用反射来完成此操作。 - M.kazem Akhgary
使用.SelectMany来展开它,然后使用你找到的答案。 - Robert McKee
使用octavioccl的答案。因为它不使用反射,所以比我的方法快100倍。所以如果我是你,我会接受他的答案而不是我的 ;) - M.kazem Akhgary
2个回答

5

由于这个链接的问题标记为c#,所以我添加了这个包含c#代码的答案。

如果嵌套列表的数量已知,您必须一遍又一遍地使用SelectMany()将所有嵌套的列表展开到字符序列中,然后从该序列制作字符串。

List<List<List<string>>> nestedList = new List<List<List<string>>>();
var result = new string(nestedList.SelectMany(x => x).SelectMany(x => x).SelectMany(x => x).ToArray());

如果嵌套列表的数量未知,则必须使用反射,因为类型未知。我没有直接使用反射,但实际上动态类型是可以的。当然,性能会非常糟糕;但它可以做到你想要的。
using Microsoft.CSharp.RuntimeBinder;

//...

private static string ConcatAll<T>(T nestedList) where T : IList
{
    dynamic templist = nestedList;
    try
    {
        while (true)
        {
            List<dynamic> inner = new List<dynamic>(templist).SelectMany<dynamic, dynamic>(x => x).ToList();
            templist = inner;
        }
    }
    catch (RuntimeBinderException)
    {
        List<object> l = templist;
        return l.Aggregate("", (a, b) => a + b);
    }
}

这是一个测试

private static void Main(string[] args)
{
    List<List<List<string>>> nestedList = new List<List<List<string>>>
    {
        new List<List<string>> {new List<string> {"Hello "}, new List<string> {"World "}},
        new List<List<string>> {new List<string> {"Goodbye "}, new List<string> {"World ", "End "}}
    };

    Console.WriteLine(ConcatAll(nestedList));
}

输出:

Hello World Goodbye World End

更新:

经过一些尝试,我最终完成了这个实现。也许可以不需要 try-catch 块。

private static string ConcatAll<T>(T nestedList) where T : IList
{
    dynamic templist = nestedList;
    while (templist.Count > 0 && !(templist[0] is char?))
    {
        List<dynamic> inner = new List<dynamic>(templist).SelectMany<dynamic, dynamic>(x =>
        {
            var s = x as string;
            if (s != null)
            {
                return s.Cast<dynamic>();
            }
            return x;
        }).ToList();
        templist = inner;
    }
    return new string(((List<object>) templist).Cast<char>().ToArray());
}

3
另一个解决方案可能是使用递归方法来展开您所有的列表:
 static IEnumerable<string> Flatten(IEnumerable enumerable)
 {
        foreach (object el in enumerable)
        {
            if (enumerable is IEnumerable<string>)
            {
                yield return (string) el;
            }
            else
            {
                IEnumerable candidate = el as IEnumerable;
                if (candidate != null)
                {
                    foreach (string nested in Flatten(candidate))
                    {
                        yield return nested;
                    }
                }
            }
        }
 }

使用这种方法,您可以将所有字符串连接起来:

 List<List<List<string>>> nestedList = new List<List<List<string>>>
                                       {
                                          new List<List<string>> {new List<string> {"Hello "}, new List<string> {"World "}},
                                          new List<List<string>> {new List<string> {"Goodbye "}, new List<string> {"World ", "End "}}
                                      };

Console.WriteLine(String.Join(" ",Flatten(nestedList))); 

这个想法来自于这篇帖子


很好的答案。我正想发表类似的东西,但无法正确运行 :-(。顺便问一下,在 else 子句中的空值检查是否必要?如果是,请解释一下原因。 - Kapol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接