2010-12-16 22 views
2

VB .NETでこれを行うにはどうすればよいですか? IEnumerableでlinq Zipメソッドを使用しようとしましたが、2つ以上の配列では機能しません。ここで IEnumerableのIEnumerableとして存在する2D配列の転置

は私がやろうとしています何のPythonでの例である( - ネストされたIEnumerableを - 私は、pだとq必要 - 別のネストされたIEnumerableをを):

>>> l=['a','b','c'] 
>>> m=[1,2,3] 
>>> n=['x','y','z'] 
>>> p=[l,m,n] 
>>> p 
[['a', 'b', 'c'], [1, 2, 3], ['x', 'y', 'z']] 
>>> q=zip(*p) 
>>> q 
[('a', 1, 'x'), ('b', 2, 'y'), ('c', 3, 'z')] 
+0

現在、新しいIEnumerableを作成するためのループでの歩留まり。私はまだネストされた郵便番号で行うことが可能かどうかを見たいと思っています。 – user544111

答えて

2

ジップの.NETバージョンはしませんPythonのように任意の数の配列を扱うことができます。あなたは二回郵便番号を呼び出す必要があります:

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

EDIT:一つの考えが直接のPythonを活用し、VB.NETからそれを呼び出すことです。私はこれがどのように処理されるのか本当にわからないし、それをすべて設定する学習曲線があるだろう。そのトピックの詳細については、「call python from c#」または「vb.net」を検索してください。

匿名タイプを動的に作成することはできません。私が思いついた最も近いアプローチは、.NET 4.0のExpandoObjectを使用することです。 VB.NETでC#のdynamicキーワードを使用するには、実際にobjectの下にあるDim o = 5のような型を指定せずにオブジェクトを初期化できるはずです。これを達成するには、おそらくOption Infer OnOption Strict Offを設定する必要があります。

次のコードでは、配列を入力として想定しています。残念ながら、Countにアクセスしようとすると、ダイナミックタイプとその他のIEnumerable<T>を混在させるのは難しくなります。 Jon Skeetに関連記事があります:Gotchas in dynamic typing。そのため私は配列についていました。 Countプロパティを使用するにはList<T>に変更できますが、多くの作業をしなくても間違いなく混在することはありません。 (興味のある人のための)

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

入れ子にされたZipは私がやったことです。しかし私のオリジナルのコレクションはオープンエンドで、3つ以上のIEnumerableを持つことができます。私はこのZipをループに入れようとしました:first.Zip(second、Function(f、s){f、s})。問題は、返されるfはIEnumerableであり、sはIEnumerableの内容であるということです。私はSelectManyでfを平坦化しようとしましたが、そこにはまってしまいました... .Firstと.Secondを使ってこの問題を解決しましたが、オープンループを実行したい場合はできません。何か案は? – user544111

+0

@ user544111が更新されました。 –

+0

これは何よりも優れています。これまでのところ、私の直面する問題を解決してくれました。新しいトリックを教えてくれました。ありがとうございました!私はあなたにupvoteするより多くの担当者を持っていればと思います... – user544111

0

あなたがサポートしたいIEnumerablesの具体的な数を持っている場合、あなたはいくつかの並べ替えを返すことができます(例えば、Ahmad Mageeds answerと同様)。一般的なケースでは、ある種のキャッシュを行う必要があり、すべての列挙型に1つのタイプのアイテムしか存在しません。次のようなものがあります。

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 
+0

Phew!これは私が1つの座席で消化する以上のものです。確かにここでいくつかのクールなコンセプト。私はこれにいくつかの時間を費やす必要があります...ありがとう! – user544111