.net 转置作为IEnumerable的IEnumerable存在的2D数组
如何在VB.NET中执行此操作?我尝试在IEnumerable上使用LINQZIP方法,但它不适用于2个以上的数组 下面是一个Python示例,说明了我正在尝试做的事情(我得到了p-嵌套IEnumerable-需要q-另一个嵌套IEnumerable):.net 转置作为IEnumerable的IEnumerable存在的2D数组,.net,vb.net,linq,.net,Vb.net,Linq,如何在VB.NET中执行此操作?我尝试在IEnumerable上使用LINQZIP方法,但它不适用于2个以上的数组 下面是一个Python示例,说明了我正在尝试做的事情(我得到了p-嵌套IEnumerable-需要q-另一个嵌套IEnumerable): NET版本的Zip不会像Python那样处理任意数量的数组。您需要给Zip打两次电话: Dim first As String() = { "a", "b", "c" } Dim second As Integer() = { 1, 2, 3
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
另一种选择是使用包含索引的重载。这种方法依赖于您正在使用的允许按索引访问的类型。为了提高性能,我不建议用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”以了解有关该主题的更多信息 挑战在于您无法动态创建匿名类型。我想到的最接近的方法是使用.NET4.0。要在VB.NET中使用C#的
dynamic
关键字,您应该能够在不指定类型的情况下初始化对象,例如Dim o=5
,因为它实际上是一个对象。您可能需要将选项推断设置为打开
和选项严格关闭
,以实现这一点
下面的代码需要数组作为输入。不幸的是,在尝试访问计数时,混合使用动态类型和其他IEnumerable
变得很困难。Jon Skeet在这里有一篇相关文章:。出于这个原因,我坚持使用数组;可以将其更改为List
,以使用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[]秒={1,2,3};
字符串[]第三个={“x”,“y”,“z”};
bool[]fourth={true,false,true};
var list=新列表{第一、第二、第三、第四};
bool isValidLength=list.All(l=>l.Length==list[0].Length);
如果(isValidLength)
{
var result=新列表();
对于(int i=0;i
如果要支持特定数量的IEnumerable,可以返回某种元组或类似结构(如)。对于一般情况,您必须进行某种缓存,最终在所有可枚举项中只有一种类型的项。大概是这样的:
Public Function Transpose(Of T)(ByVal source As IEnumerable(Of IEnumerable(Of T))) As IEnumerable(Of IEnumerable(Of T))
If source is Nothing then Throw New ArgumentNullException("source")
Return New TransposeEnumerable(Of T)(source)
End Function
Friend NotInheritable Class TransposeEnumerable(Of T)
Implements IEnumerable(Of IEnumerable(Of T))
Public Sub New(ByVal base As IEnumerable(Of IEnumerable(Of T)))
_base = base
End Sub
Private ReadOnly _base As IEnumerable(Of IEnumerable(Of T))
Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of IEnumerable(Of T)) Implements System.Collections.Generic.IEnumerable(Of IEnumerable(Of T)).GetEnumerator
Return New TransposeEnumerator(Me)
End Function
Private Function GetObjectEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
Return Me.GetEnumerator()
End Function
Private NotInheritable Class TransposeEnumerator
Implements IEnumerator(Of IEnumerable(Of T))
Public Sub New(ByVal owner As TransposeEnumerable(Of T))
_owner = owner
_sources = owner.Select(Function(e) e.GetEnumerator()).ToList()
End Sub
Private disposedValue As Boolean
Public Sub Dispose() Implements IDisposable.Dispose
If Not Me.disposedValue Then
If _sources IsNot Nothing Then
For Each e In _sources
If e IsNot Nothing Then e.Dispose()
Next
End If
End If
Me.disposedValue = True
End Sub
Private ReadOnly _owner As TransposeEnumerable(Of T)
Private _sources As New List(Of IEnumerator(Of T))
Private _current As IEnumerable(Of T)
Public ReadOnly Property Current() As IEnumerable(Of T) Implements System.Collections.Generic.IEnumerator(Of IEnumerable(Of T)).Current
Get
Return _current
End Get
End Property
Private ReadOnly Property CurrentObject() As Object Implements System.Collections.IEnumerator.Current
Get
Return Me.Current
End Get
End Property
Public Function MoveNext() As Boolean Implements System.Collections.IEnumerator.MoveNext
Dim success As Boolean = _sources.All(Function(s) s.MoveNext())
If success Then
_current = _sources.Select(Function(s) s.Current).ToList().AsEnumerable()
End If
Return success
End Function
Public Sub Reset() Implements System.Collections.IEnumerator.Reset
Throw New InvalidOperationException("This enumerator does not support resetting.")
End Sub
End Class
End Class
嵌套式拉链也是我尝试过的。但我的原始收藏是开放式的,可以有3个以上的IEnumerable。我试图将这个Zip放在一个循环中:first.Zip(第二,函数(f,s){f,s})。问题是返回的f是IEnumerable,而s是IEnumerable的内容。然后我尝试用SelectMany展平f,结果被卡住了。。。您通过使用.First和.Second解决了这个问题,但如果我想运行开放式循环,就不能这样做。有什么想法吗?这比我目前能想到的任何东西都好,它解决了我眼前的问题,同时教了我一些新的技巧-非常感谢!但愿我有更多的代表投票给你…呸!这比我一次能消化的还要多。当然这里有一些很酷的概念。我得花点时间在这上面。。。谢谢当前在循环中使用yield创建新的IEnumerable。我仍然想看看是否可以使用嵌套的Zip。。。
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();
}
}
Public Function Transpose(Of T)(ByVal source As IEnumerable(Of IEnumerable(Of T))) As IEnumerable(Of IEnumerable(Of T))
If source is Nothing then Throw New ArgumentNullException("source")
Return New TransposeEnumerable(Of T)(source)
End Function
Friend NotInheritable Class TransposeEnumerable(Of T)
Implements IEnumerable(Of IEnumerable(Of T))
Public Sub New(ByVal base As IEnumerable(Of IEnumerable(Of T)))
_base = base
End Sub
Private ReadOnly _base As IEnumerable(Of IEnumerable(Of T))
Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of IEnumerable(Of T)) Implements System.Collections.Generic.IEnumerable(Of IEnumerable(Of T)).GetEnumerator
Return New TransposeEnumerator(Me)
End Function
Private Function GetObjectEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
Return Me.GetEnumerator()
End Function
Private NotInheritable Class TransposeEnumerator
Implements IEnumerator(Of IEnumerable(Of T))
Public Sub New(ByVal owner As TransposeEnumerable(Of T))
_owner = owner
_sources = owner.Select(Function(e) e.GetEnumerator()).ToList()
End Sub
Private disposedValue As Boolean
Public Sub Dispose() Implements IDisposable.Dispose
If Not Me.disposedValue Then
If _sources IsNot Nothing Then
For Each e In _sources
If e IsNot Nothing Then e.Dispose()
Next
End If
End If
Me.disposedValue = True
End Sub
Private ReadOnly _owner As TransposeEnumerable(Of T)
Private _sources As New List(Of IEnumerator(Of T))
Private _current As IEnumerable(Of T)
Public ReadOnly Property Current() As IEnumerable(Of T) Implements System.Collections.Generic.IEnumerator(Of IEnumerable(Of T)).Current
Get
Return _current
End Get
End Property
Private ReadOnly Property CurrentObject() As Object Implements System.Collections.IEnumerator.Current
Get
Return Me.Current
End Get
End Property
Public Function MoveNext() As Boolean Implements System.Collections.IEnumerator.MoveNext
Dim success As Boolean = _sources.All(Function(s) s.MoveNext())
If success Then
_current = _sources.Select(Function(s) s.Current).ToList().AsEnumerable()
End If
Return success
End Function
Public Sub Reset() Implements System.Collections.IEnumerator.Reset
Throw New InvalidOperationException("This enumerator does not support resetting.")
End Sub
End Class
End Class