展平可能包含数组的对象数组

我有一个IEnumerable ,它可能包含也可能不包含一些嵌套集合。 例如,我的起点可能如下所示:

 [ "foo", 2, [1, 2, 3, 4], "bar" ] 

我想把它压平为:

 [ "foo", 2, 1, 2, 3, 4, "bar" ] 

我在想SelectMany应该在这里工作但是找不到合适的组合。 我可以蛮力,但我认为应该有一个更优雅的解决方案。

 IEnumerable source = new object[] { "test", 1, new[] { 1, 2, 3 }, "test" }; var result = source .SelectMany(x => x is Array ? ((IEnumerable)x).Cast() : Enumerable.Repeat(x, 1)); 

要使它与嵌套数组一起使用,使lambda递归:

 IEnumerable source = new object[] { "test", 1, new object[] { 1, 2, new [] { "nested", "nested2" } }, "test" }; Func, IEnumerable> flatten = null; flatten = s => s.SelectMany(x => x is Array ? flatten(((IEnumerable)x).Cast()) : Enumerable.Repeat(x, 1)); var result = flatten(source); 

略微缩短的递归替代方案:

 IEnumerable source = new object[] { "test", 1, new object[] { 1, 2, new [] { "nested", "nested2" } }, "test" }; Func, IEnumerable> flatten = null; flatten = s => s == null ? null : s.SelectMany(x => flatten(x as IEnumerable) ?? new [] { x } ); var result = flatten(source); 

这有点讨厌,但有效..假设只有一个级别:

 a.SelectMany(t => (t is IEnumerable) ? (IEnumerable)t : new object[] {t}) 

我怀疑最“优雅”的解决方案是写一个扩展。

 public static IEnumerable Flatten(this IEnumerable @this) { foreach (var item in @this) { if (item is IEnumerable) { foreach (var subitem in Flatten((IEnumerable)item)) { yield return subitem; } } else yield return item; } }