IEnumerable<object[]> 和 IEnumerable[] 之间的优雅转换<object>



有什么方法可以将IEnumerable<int[]>转换为IEnumerable<int>[]吗?具体来说,我有以下IEnumerable:

IEnumerable<int[]> data = new List<int[]>()
{
new int[]{1,11},
new int[]{2,22},
new int[]{3,33},
new int[]{4,44},
// ...
// ...
};

我想把它变成以下形状:

IEnumerable<int>[] data = new List<int>[] 
{ 
new List<int>(){1,2,3,4 },
new List<int>(){11,22,33,44}
};

到目前为止,我提出的唯一解决方案如下:

public static IEnumerable<int>[] Convert(IEnumerable<int[]> data)
{
var length = data.First().Length;
var output = new List<int>[length];
for (int i = 0; i < length; i++)   
output[i] = new List<int>();
foreach (var entry in data) 
{
for (int i = 0; i < length; i++)    
{
output[i].Add(entry[i]);
}
}
return output;
}

但这并不理想,因为我需要对整个数据集进行迭代。所需的解决方案是使用LINQ或内置迭代器模式特性(yield return(。这个问题有更好的解决办法吗?

如果你不介意data的多次枚举,你可以这样做:

public static IEnumerable<int>[] Convert(IEnumerable<int[]> data)
{
var length = data.First().Length;
var output = new IEnumerable<int>[length];
for (int i = 0; i < length; i++)
{
output[i] = CustomEnumerable(i);
}
return output;
IEnumerable<int> CustomEnumerable(int index)
{
foreach (var entry in data) 
{
yield return entry[index];
}
}
}

正如您所看到的,我返回的不是填充列表,而是自定义的IEnumerable<int>,它们是用本地迭代器函数(使用yield return(创建的。

如果你只想迭代data一次,你可以这样做:

IEnumerable<int>[] Convert(IEnumerable<int[]> data)
{
var found = new List<int[]>();
using var enumerator = data.GetEnumerator();
var proxy = ProxyEnumerable();

var length = proxy.First().Length;
var output = new IEnumerable<int>[length];
for (int i = 0; i < length; i++)
{
output[i] = CustomEnumerable(i);
}
return output;
IEnumerable<int> CustomEnumerable(int index)
{
foreach (var entry in proxy) 
{
yield return entry[index];
}
}

IEnumerable<int[]> ProxyEnumerable()
{    
foreach (var value in found)
{
yield return value;
}
while (enumerator.MoveNext())
{
var value = enumerator.Current;
found.Add(value);
yield return value;
}
}
}

在这里,我添加了另一个IEnumerable<int[]>,当我们对其进行迭代时,它正在填充缓存List<int[]>。因此,data只迭代一次,随后的迭代使用缓存。

在线试用。

我对LINQ有一个简短的建议。通过下面的例子,你可以得到一个锯齿状阵列

var maxLength = data.Max(x => x.Length);
var converted = new IEnumerable<int>[maxLength]
.Select((dst, index) => data
.Select(src => src.Length > index ? src[index] : default)
.Where(n => n != default));

有了这个,你可以把你的源阵列切割成矩阵

var minLength = data.Min(x => x.Length);
var converted = new IEnumerable<int>[minLength]
.Select((dst, index) => data
.Select(src => src[index]));

相关内容

最新更新