Reputation: 519
I am trying to write some methods to deal with multi-layered IEnumerable object in C#. The following example is the method named "ConsoleWrite" which used for printing each string in IEnumerable object to console.
public void ConsoleWrite(IEnumerable<string> StringData)
{
foreach (var EachString in StringData)
{
Console.Write(EachString);
}
}
The usage of "ConsoleWrite" method.
List<string> Test1 = new List<string>();
Test1.Add("123");
Test1.Add("456");
ConsoleWrite(Test1);
It works well and the output is "123456". However, when it comes to the List<List<string>>
case, this ConsoleWrite method needs to be overloading as below.
public void ConsoleWrite(IEnumerable<IEnumerable<string>> StringData)
{
foreach (var EachString in StringData)
{
ConsoleWrite(EachString);
}
}
The test of the case List<List<string>>
.
List<List<string>> Test2 = new List<List<string>>();
Test2.Add(Test1);
Test2.Add(Test1);
ConsoleWrite(Test2)
Furthermore, for the case List<List<List<string>>>
, this ConsoleWrite method needs to be overloading as public void ConsoleWrite(IEnumerable<IEnumerable<IEnumerable<string>>> StringData)
. I am wondering that is there any way to deal with arbitrarily nested List IEnumerable<...<IEnumerable<string>>>
easily and without overloading one-by-one?
Any suggestions are welcome.
Upvotes: 1
Views: 362
Reputation: 81553
You could just the non generic IEnumerable
, some pattern matching and recursion
public static void ConsoleWrite(IEnumerable source)
{
foreach (var item in source)
if (item is string str)
Console.WriteLine(str);
else if (item is IEnumerable enumerable)
ConsoleWrite(enumerable);
}
Example
var list = new List<string> {"1", "2", "3"};
ConsoleWrite(list);
var list2 = new List<List<string>>
{
new List<string>(){"4", "5", "6"},
new List<string>(){"7", "8", "9"}
};
ConsoleWrite(list2);
Output
1
2
3
4
5
6
7
8
9
Another more generic way would be to create an extension method, Like SelectMany
with recursion
public static class Extensions
{
public static IEnumerable<T> FlattenMany<T>(this IEnumerable source)
{
foreach (var item in source)
if (item is T t)
yield return t;
else if (item is IEnumerable enumerable)
foreach (var elem in enumerable.FlattenMany<T>())
yield return elem;
}
}
Usage
var list2 = new List<List<string>>
{
new List<string>() {"4", "5", "6"},
new List<string>() {"7", "8", "9"}
};
var results = list2.FlattenMany<string>();
Upvotes: 3