4

My question is almost same as this one, but the List dimension is n. How to concat all strings inside a List<List<List...<string>> (n dimension list) using LINQ ?


NOTE: Interested for both cases, n is known or unknown

4
  • using c# right? because the same question is tagged c#. Commented Nov 20, 2015 at 21:17
  • you should do this using reflection since the type of list is not known. Commented Nov 20, 2015 at 21:25
  • Use .SelectMany to flatten it, and then use the answer you found. Commented Nov 20, 2015 at 21:47
  • use octavioccl`s answer. since it doesnt use reflection. its hundred times faster than my approach. so if i were you i would accept his answer instead ;) Commented Nov 20, 2015 at 22:56

2 Answers 2

5

Since the linked question is tagged as c# so i add this answer with c# code.

If the number of nested lists are known You have to use SelectMany() over and over to unwrap all the nested lists to sequence of chars. then make string out of that sequence.

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

If the number of nested lists are not known you have to use reflection, since the type is not known. I didnt used reflection directly but actually dynamic type does. The performance would be terrible here of course ;) but it does what you want.

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

Here is the test

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

Outputs:

Hello World Goodbye World End

Update:

After a bit fiddling i ended up this implementation. maybe better without 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());
}
Sign up to request clarification or add additional context in comments.

Comments

3

Another solution could be using a recursive method to flatten all your lists:

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

With this method you can concat all the strings this way:

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

This idea was taken from this post.

1 Comment

Great answer. I was about to post something similar, but couldn't get it to work correctly :-(. By the way, is that null check in else clause necessary? If it is, could you please explain why?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.