.NET 版本的 Zip 不会像 Python 那样处理任意数量的数组。您需要调用 Zip 两次:
Dim first As String() = { "a", "b", "c" }
Dim second As Integer() = { 1, 2, 3 }
Dim third As String() = { "x", "y", "z" }
Dim query = first.Zip(second, Function(f, s) New With { .First = f, .Second = s }) _
.Zip(third, Function(o, t) New With { o.First, o.Second, .Third = t })
For Each item in query
Console.WriteLine("{0}, {1}, {2}", item.First, item.Second, item.Third)
Next
另一种选择是使用包含索引的重载Enumerable.Select method。这种方法依赖于您正在使用的允许按索引访问的类型。出于性能目的,我不建议使用 ElementAt 方法替换索引访问。此外,这种方法假设所有集合都具有相同的长度,否则会抛出异常。它的工作原理如下:
Dim query2 = first.Select(Function(f, i) New With { .First = f, .Second = second(i), .Third = third(i) })
编辑:一种想法是直接利用 Python 并从 VB.NET 调用它。我不确定这将如何处理,并且会有一个学习曲线来设置它。搜索“从 c# 调用 python”或从“vb.net”获取有关该主题的更多信息。
挑战在于您不能动态创建匿名类型。我想出的最接近的方法是使用 .NET 4.0 的ExpandoObject。要在 VB.NET 中使用 C# 的 dynamic 关键字,您应该能够在不指定类型的情况下初始化对象,例如 Dim o = 5,因为它实际上是下面的 object。您可能需要设置 Option Infer On 和 Option Strict Off 来实现这一点。
以下代码需要数组作为输入。不幸的是,在尝试访问 Count 时,混合动态类型和其他 IEnumerable<T>s 变得具有挑战性。 Jon Skeet 在这里有一篇相关的文章:Gotchas in dynamic typing。出于这个原因,我坚持使用数组;可以将其更改为List<T> 以使用Count 属性,但绝对不是没有大量工作的混合。
VB.NET
Dim first As String() = { "a", "b", "c" }
Dim second As Integer() = { 1, 2, 3 }
Dim third As String() = { "x", "y", "z" }
Dim fourth As Boolean() = { true, false, true }
Dim list As New List(Of Object) From { first, second, third, fourth }
' ensure the arrays all have the same length '
Dim isValidLength = list.All(Function(c) c.Length = list(0).Length)
If isValidLength
Dim result As New List(Of ExpandoObject)()
For i As Integer = 0 To list(i).Length - 1
Dim temp As New ExpandoObject()
For j As Integer = 0 To list.Count - 1
CType(temp, IDictionary(Of string, Object)).Add("Property" + j.ToString(), list(j)(i))
Next
result.Add(temp)
Next
' loop over as IDictionary '
For Each o As ExpandoObject In result
For Each p in CType(o, IDictionary(Of string, Object))
Console.WriteLine("{0} : {1}", p.Key, p.Value)
Next
Console.WriteLine()
Next
' or access via property '
For Each o As Object In result
Console.WriteLine(o.Property0)
Console.WriteLine(o.Property1)
Console.WriteLine(o.Property2)
Console.WriteLine(o.Property3)
Console.WriteLine()
Next
End If
C# 等效项(任何感兴趣的人)
string[] first = { "a", "b", "c" };
int[] second = { 1, 2, 3 };
string[] third = { "x", "y", "z" };
bool[] fourth = { true, false, true };
var list = new List<dynamic> { first, second, third, fourth };
bool isValidLength = list.All(l => l.Length == list[0].Length);
if (isValidLength)
{
var result = new List<ExpandoObject>();
for (int i = 0; i < list[i].Length; i++)
{
dynamic temp = new ExpandoObject();
for (int j = 0; j < list.Count; j++)
{
((IDictionary<string, object>)temp).Add("Property" + j, list[j][i]);
}
result.Add(temp);
}
// loop over as IDictionary
foreach (ExpandoObject o in result)
{
foreach (var p in (IDictionary<string, object>)o)
Console.WriteLine("{0} : {1}", p.Key, p.Value);
Console.WriteLine();
}
// or access property via dynamic
foreach (dynamic o in result)
{
Console.WriteLine(o.Property0);
Console.WriteLine(o.Property1);
Console.WriteLine(o.Property2);
Console.WriteLine(o.Property3);
Console.WriteLine();
}
}