如何展平数组数组?

时间:2018-12-13 12:51:36

标签: c# arrays linq

我有一个包含以下元素的数组:

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

我尝试展平的真实对象是从CSV导入数据到数组数组,然后将其连接到字段的值上:

    var q =
        from c in list
        join p in vocatives on c.Line[name1].ToUpper() equals p.first_name.ToUpper() into ps
        from p in ps.DefaultIfEmpty()
        select new object[] { c.Line,  p == null ? "(No vocative)" : p.vocative, p == null ? "(No sex)" : p.sex }; 

我想展平该字符串数组以获得:

string[] {
    new string[]{ "1","2","3","4" },
    new string[]{ "5","6","7","8" },
    new string[]{ "9","10","11","12","13" }
}

我已经有一个解决方案可以循环执行此操作,虽然它不是性能方面的问题,但是似乎可以正常工作。

我尝试使用SelectMany,但无法解决问题。

非常感谢您的反馈;) 我试过npo的答案:

var result = schools.Select(z => z.SelectMany(y=> y.GetType().IsArray 
           ? (object[])y : new object[] { y })
);

但是CSVwriter类方法仅接受显式键入:

IEnumerable<string[]>

那么如何在linq中做到这一点,我尝试过:

List<string[]> listOflists = (List<string[]>)result;

但不幸的是,InvalidCastException到了。

4 个答案:

答案 0 :(得分:4)

第一步,您必须将数据标准化为一种类型。然后,您可以根据需要遍历它们。因此,首先创建一种将值从特定点展平到任意深度的方法:

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

现在您可以在顶层进行迭代以获取所有值的单个数组:

// Produces one array => ["1", "2", "3", "4", ...]
var allFlat = schools.FlattenArrays().OfType<string>().ToArray();

或者您可以创建一个深度更深的单个数组:

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

答案 1 :(得分:1)

根据评论,由于您的内部数组混合了string[]string的元素,因此直接在Linq中执行此操作可能并不容易。

但是,借助辅助函数(我称为Flattener),您可以手动分支处理这两种内部类型,以返回数组中的元素(如果它是{{1} }),或者将单个元素返回为可枚举(如果不是)。然后string[]可以用来展平内部层次,但是您似乎想不展平外部层次:

SelectMany

哪个返回类型为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)));

其中杂乱的拆包工作是由以下人员完成的:

IEnumerable<IEnumerable<string>>

请注意,上面使用了C#7的模式匹配功能。

结果截图由LinqPad提供:

enter image description here

答案 2 :(得分:0)

如果您想通过linq进行操作,请参考以下示例

     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(z => z.SelectMany(y=> y.GetType().IsArray ? (object[])y : new object[] { y }));

答案 3 :(得分:0)

提出的解决方案专用于转换任何类型的int数组,常规,锯齿状,嵌套这些最后一个来自javascript及其对象表示法,但也可以将它们实现为C#中复杂的锯齿状对象数组。),可以实现为简单的一维整数数组。

要适应您的请求,只需将锯齿状数组的string类型元素更改为int类型。

这里是C#函数:

    public static int[] getFlattenedIntArray(object jaggedArray)
    {

        var flattenedArray = new List<int>();

        var jaggedArrayType = jaggedArray.GetType();
        var expectedType = typeof(int);

        if (jaggedArrayType.IsArray)
        {
            if (expectedType.IsAssignableFrom(jaggedArrayType.GetElementType()))
            {
                foreach (var el in jaggedArray as int[])
                {
                    flattenedArray.Add(el);
                }
            }
            else
            {
                foreach (var el in jaggedArray as object[])
                {
                    foreach (var retIntEl in getFlattenedIntArray(el))
                    {
                        flattenedArray.Add(retIntEl);
                    }
                }

            }
        }
        else if (jaggedArrayType == expectedType)
        {
            flattenedArray.Add((int)jaggedArray);
        }
        else
        {
            return new int[0];
        }

        return flattenedArray.ToArray();
    }

在这个小提琴中尝试:https://dotnetfiddle.net/5HGX96