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

时间:2014-02-04 20:08:47

标签: c# arrays linq

我有IEnumerable<object>,可能包含也可能不包含某些嵌套集合。例如,我的出发点可能如下所示:

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

我想把它压平为:

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

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

3 个答案:

答案 0 :(得分:5)

IEnumerable<object> source = new object[] { "test", 1, new[] { 1, 2, 3 }, "test" };

var result = source .SelectMany(x => x is Array ? ((IEnumerable)x).Cast<object>() : Enumerable.Repeat(x, 1));

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

IEnumerable<object> source = new object[] { "test", 1, new object[] { 1, 2, new [] { "nested", "nested2" } }, "test" };

Func<IEnumerable<object>, IEnumerable<object>> flatten = null;
flatten = s => s.SelectMany(x => x is Array ? flatten(((IEnumerable)x).Cast<object>()) : Enumerable.Repeat(x, 1));

var result = flatten(source);

答案 1 :(得分:3)

稍微短一些的递归替代方案:

IEnumerable<object> source = new object[] { "test", 1, new object[] { 1, 2, new [] { "nested", "nested2" } }, "test" };

Func<IEnumerable<object>, IEnumerable<object>> flatten = null;
flatten = s => s == null ? null : s.SelectMany(x => 
   flatten(x as IEnumerable<object>) ?? new [] { x }
);
var result = flatten(source);

答案 2 :(得分:2)

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

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

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

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