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

3

我有一个 IEnumerable<object>,其中可能包含一些嵌套集合。例如,我的起点可能看起来像这样:

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

我希望将其展平为:

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

我认为在这里使用SelectMany可能会有帮助,但是我还没有找到正确的组合方式。虽然我可以采用粗暴的方法,但我认为应该有更加优雅的解决方案。


你看过这个吗:http://blog.mijalko.com/2009/12/flatten-array-of-arrays-using-linq.html - Mike Cheel
@MikeCheel:实际上我试过了,但那不是完全一样的东西。那是一个列表的列表。这是一个对象列表,其中有些可能是列表。我想选择既不是列表的对象,也要选择每个列表的内容。 - Matt Burland
你的嵌套是否总是有两层深度,还是可能会有更深层次的嵌套数组? - nemesv
@nemesv:目前只有两个级别。我不预计会更深入(如果确实需要,我将不得不重新考虑整个事情!) - Matt Burland
3
你的列表中可以包含哪些类型的列表对象?我问这个问题是因为"foo"是一个字符串,它实现了IEnumerable<char>,听起来你不想要的是['f', 'o', 'o', ...]这种形式。 - Joel Rondeau
显示剩余2条评论
3个回答

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

2
那样做无法处理嵌套数组。 - SLaks
@SLaks 我已经更新了我的答案,加入了递归解决方案。 - MarcinJuraszek

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

这个方法有点不太好,但是只适用于一个层级:

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

1
很聪明!不过为了清晰起见,我还是更喜欢我的。 - Blorgbeard
是的,超过一定程度后,简洁和清晰可能会互相排斥。 - SLaks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接