How do I flatten an array of arrays?
In a first step, you have to normalize the data to one kind of type. Then you can iterate over them as you like. So at first create a method to flatten the values from a specific point to an arbitrary depth:
public static class Extensions
{
public static IEnumerable<object> FlattenArrays(this IEnumerable source)
{
foreach (var item in source)
{
if (item is IEnumerable inner
&& !(item is string))
{
foreach (var innerItem in inner.FlattenArrays())
{
yield return innerItem;
}
}
yield return item;
}
}
}
Now you can either iterate on the top level to get a single array of all values:
// Produces one array => ["1", "2", "3", "4", ...]
var allFlat = schools.FlattenArrays().OfType<string>().ToArray();
Or you can create individual array one depth deeper:
foreach (var item in schools)
{
// Produces an array for each top level e.g. ["5", "6", "7", "8"]
var flat = item.FlattenArrays().OfType<string>().ToArray();
}
As per the comments, because your inner array mixes elements of string[]
and string
, it likely won't be trivial to do this directly in Linq.
However, with the assistance of a helper function (I've called Flattener
) you can branch the handling of both of the inner types manually to either return the elements in the array (if it's string[]
), or to return the single element as an enumerable, if it's not. SelectMany
can then be used to flatten the inner level, but the outer level seemingly you want to leave unflattened:
i.e.
var schools = new [] {
new object[]{new[]{"1","2"}, "3","4"},
new object[]{new[]{"5","6"}, "7","8"},
new object[]{new[]{"9","10","11"}, "12","13"}
};
var result = schools
.Select(s => s.SelectMany(o => Flattener(o)));
Which returns a type of IEnumerable<IEnumerable<string>>
Where the messy unpacking bit done by:
public IEnumerable<string> Flattener(object o)
{
if (o is IEnumerable<string> strings)
{
return strings;
}
if (o is string s)
{
return new[]{s};
}
return new[]{"?"};
}
Note the above uses the pattern matching capabilities of C#7.
Result screenshot courtesy of LinqPad: