【问题标题】:Concat all strings inside a List<List<string>> using LINQ使用 LINQ 连接 List<List<string>> 中的所有字符串
【发布时间】:2016-02-23 11:36:05
【问题描述】:

我的问题与one 几乎相同,但列表维度为 n。 如何使用 LINQ 连接 List&lt;List&lt;List...&lt;string&gt;&gt;(n 维列表)中的所有字符串?


注意:对这两种情况都感兴趣,nknownunknown

【问题讨论】:

  • 使用 c# 对吗?因为同一个问题被标记为 c#。
  • 您应该使用反射来执行此操作,因为列表的类型未知。
  • 使用.SelectMany 将其展平,然后使用您找到的答案。
  • 使用octavioccl`s answer。因为它不使用反射。它比我的方法快一百倍。所以如果我是你,我会接受他的回答;)

标签: c# .net linq


【解决方案1】:

由于链接的问题被标记为 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());
}

【讨论】:

    【解决方案2】:

    另一种解决方案可能是使用递归方法来展平所有列表:

     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))); 
    

    这个想法来自post

    【讨论】:

    • 很好的答案。我正要发布类似的内容,但无法使其正常工作:-(。顺便说一下,else 子句中的空值检查是否必要?如果是,您能解释一下原因吗?
    猜你喜欢
    • 2010-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 2013-08-28
    • 2012-04-06
    相关资源
    最近更新 更多