我有一个包含以下元素的数组:
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
到了。
答案 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提供:
答案 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