作为IEnumerable的IEnumerable存在的转置2D数组 [英] transpose 2D array that exists as IEnumerable of IEnumerable

查看:97
本文介绍了作为IEnumerable的IEnumerable存在的转置2D数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在VB .NET中执行此操作?我尝试在IEnumerable上使用linq Zip方法,但不适用于2个以上的数组.

How do I do this in VB .NET? I tried using the linq Zip method on IEnumerable but it does not work for more than 2 arrays.

这是我想做的Python示例(我有p-嵌套的IEnumerable-需要q-另一个嵌套的IEnumerable):

Here is an example in Python of what I am trying to do(I got p - nested IEnumerable - and need q - another nested 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')]

推荐答案

.net版本的Zip无法像Python那样处理任意数量的数组.您需要两次致电Zip:

The .NET version of Zip won't handle an arbitrary number of arrays the way Python's appears to do. You'll need to call Zip twice:

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方法包括索引.这种方法依赖于您正在使用的类型,允许按索引访问.我不建议出于性能目的用ElementAt方法代替索引访问.同样,此方法假定所有集合的长度相同,否则将引发异常.它的工作方式如下:

Another option would be to use the overloaded Enumerable.Select method that includes the index. This approach relies on the types you're working with allowing access by index. I wouldn't recommend substituting index access with the ElementAt method for performance purposes. Also, this approach assumes all collections have the same length, otherwise it will throw an exception. It would work as follows:

Dim query2 = first.Select(Function(f, i) New With { .First = f, .Second = second(i), .Third = third(i) })


编辑:一种想法是直接利用Python并从VB.NET调用它.我不太确定如何处理,是否有学习曲线可以设置所有内容.搜索从c#调用python"或从"vb.net"搜索有关该主题的更多信息.


One thought is to leverage Python directly and call it from VB.NET. I'm not really sure how this would be handled, and there will be a learning curve to set it all up. Search for "call python from c#" or from "vb.net" for more on that topic.

挑战在于您不能动态创建匿名类型.我想出的最接近的方法是使用.NET 4.0的 ExpandoObject .要在VB.NET中使用C#的dynamic关键字,您应该能够在不指定类型的情况下初始化对象,例如Dim o = 5,因为它实际上是下面的object.您可能需要设置Option Infer OnOption Strict Off才能实现.

The challenge is you can't dynamically create an anonymous type. The closest approach I came up with is to use .NET 4.0's ExpandoObject. To use C#'s dynamic keyword in VB.NET you should be able to initialize an object without specifying the type, such as Dim o = 5 since it's really an object underneath. You'll probably need to set Option Infer On and Option Strict Off to achieve that.

以下代码期望将数组作为输入.不幸的是,在尝试访问Count时,将动态类型和其他IEnumerable<T>混合使用变得很困难.乔恩·斯凯特(Jon Skeet)在这里有相关的文章:动态类型化中的陷阱.因此,我坚持使用数组.可以将其更改为List<T>以使用Count属性,但绝对不需大量工作.

The following code expects arrays as input. Unfortunately mixing dynamic types and other IEnumerable<T>s becomes challenging when attempting to access the Count. Jon Skeet has a relevant article about it here: Gotchas in dynamic typing. For that reason I stuck with arrays; it can be changed to List<T> to use the Count property, but definitely not a mixture without a lot of work.

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

这篇关于作为IEnumerable的IEnumerable存在的转置2D数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆