将算法从 C# 转换为 VB.NET 失败

发布于 2024-11-10 03:50:31 字数 1570 浏览 4 评论 0原文

我正在尝试将以下算法从 C# 转换为 VB.NET,但我所拥有的 VB.NET 产生的结果与我的 C# 算法不同,有人可以告诉我在转换过程中哪里出了问题吗?

public static IEnumerable<T[]> Combinations<T>(this IEnumerable<T> elements, int k)
{
    List<T[]> result = new List<T[]>();

    // single combination
    if (k == 0)
    {
        result.Add(new T[0]);
    }
    else
    {
        int current = 1;
        foreach (T element in elements)
        { 
            //combine each element with k-1 combinations of subsequent elements
            result.AddRange(elements
                .Skip(current++)
                .Combinations(k - 1)
                .Select(combination => (new T[] { element }).Concat(combination).ToArray())
                );
        }
    }
    return result;
}

这就是我在 VB.NET 中遇到的情况:

<Extension()>
Public Function Combinations(Of T)(ByRef elements As IEnumerable(Of T), ByVal k As Integer) As IEnumerable(Of T())

    Dim result As New List(Of T())()

    'single combination'
    If k = 0 Then
        result.Add(New T(-1) {})
    Else
        Dim current As Integer = 0

        For Each element As T In elements
            'combine each element with k - 1 combinations of subsequent elements'
            Dim local As T = element
            result.AddRange(elements.Skip(current = current + 1).Combinations(k - 1).Select(Function(combs) (New T() {local}).Concat(combs).ToArray()))
        Next
    End If

    Return result
End Function

出了点问题,但我不确定是什么,我猜问题出在 lambda 中的某个地方。

有人能指出我的转换做错了什么吗?

I'm trying to convert the following algorithm from C# to VB.NET and the VB.NET I have is not producing the same results as my C# algorithm, can someone tell me where I've gone wrong in my conversion?

public static IEnumerable<T[]> Combinations<T>(this IEnumerable<T> elements, int k)
{
    List<T[]> result = new List<T[]>();

    // single combination
    if (k == 0)
    {
        result.Add(new T[0]);
    }
    else
    {
        int current = 1;
        foreach (T element in elements)
        { 
            //combine each element with k-1 combinations of subsequent elements
            result.AddRange(elements
                .Skip(current++)
                .Combinations(k - 1)
                .Select(combination => (new T[] { element }).Concat(combination).ToArray())
                );
        }
    }
    return result;
}

This is what I've got in VB.NET:

<Extension()>
Public Function Combinations(Of T)(ByRef elements As IEnumerable(Of T), ByVal k As Integer) As IEnumerable(Of T())

    Dim result As New List(Of T())()

    'single combination'
    If k = 0 Then
        result.Add(New T(-1) {})
    Else
        Dim current As Integer = 0

        For Each element As T In elements
            'combine each element with k - 1 combinations of subsequent elements'
            Dim local As T = element
            result.AddRange(elements.Skip(current = current + 1).Combinations(k - 1).Select(Function(combs) (New T() {local}).Concat(combs).ToArray()))
        Next
    End If

    Return result
End Function

Something is wrong, but I'm not sure what, I'm guessing the problem is somewhere in the lambda.

Can anybody point out what I've done wrong with my conversion?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

阪姬 2024-11-17 03:50:31

使用代码转换器...

<System.Runtime.CompilerServices.Extension> _
Public Shared Function Combinations(Of T)(elements As IEnumerable(Of T), k As Integer) As IEnumerable(Of T())
    Dim result As New List(Of T())()

    ' single combination
    If k = 0 Then
        result.Add(New T(-1) {})
    Else
        Dim current As Integer = 1
        For Each element As T In elements
            'combine each element with k-1 combinations of subsequent elements

            result.AddRange(elements.Skip(System.Math.Max(System.Threading.Interlocked.Increment(current),current - 1)).Combinations(k - 1).[Select](Function(combination) (New T() {element}).Concat(combination).ToArray()))
        Next
    End If

    Return result
End Function

Use a code converter...

<System.Runtime.CompilerServices.Extension> _
Public Shared Function Combinations(Of T)(elements As IEnumerable(Of T), k As Integer) As IEnumerable(Of T())
    Dim result As New List(Of T())()

    ' single combination
    If k = 0 Then
        result.Add(New T(-1) {})
    Else
        Dim current As Integer = 1
        For Each element As T In elements
            'combine each element with k-1 combinations of subsequent elements

            result.AddRange(elements.Skip(System.Math.Max(System.Threading.Interlocked.Increment(current),current - 1)).Combinations(k - 1).[Select](Function(combination) (New T() {element}).Concat(combination).ToArray()))
        Next
    End If

    Return result
End Function
§对你不离不弃 2024-11-17 03:50:31

我根本不是 VB 专家,但问题可能源于以下任一原因:

current = current + 1current++ 不同。它(基本上)与++current相同。它们有不同的行为。

由于 VB 不直接支持内联后递增运算符,我能想到的最接近的无错误实现是(在 C# 中,因为我不知道 VB):

int current = 0;
Func<int> getCurrentThenIncrement = () =>
{
    int previous = current;
    current = current + 1;
    return previous;
};

// ...
.Skip(getCurrentThenIncrement())

或者,它可能源于:

Public Function Combinations(Of T)(ByRef elements ...

当我使用 .Net Reflector 时看看它并将其“转换”为 VB,elements 似乎是 ByVal

I'm no expert on VB at all, but the problem might stem from either:

current = current + 1 is not the same as current++. It is (basically) the same as ++current. These have way different behavior.

Since VB doesn't support inline post-increment operators directly, the closest bug-free implementation I can think of is (in C#, since I don't know VB):

int current = 0;
Func<int> getCurrentThenIncrement = () =>
{
    int previous = current;
    current = current + 1;
    return previous;
};

// ...
.Skip(getCurrentThenIncrement())

Or, it could stem from:

Public Function Combinations(Of T)(ByRef elements ...

When I use .Net Reflector to look at it and "convert" it to VB, elements seems to be ByVal.

分分钟 2024-11-17 03:50:31

据我所知,根本不需要就地增加电流。只需在 Linq 表达式之后增加它即可。另一方面,您应该使用 1 初始化 current,与 C# 中相同。

此外,你的“基本情况”有点奇怪;你可以这样写:

result.Add(New T() { })

不需要-1

There’s no need for the in-place increment of current at all, as far as I can see. Just increment it after the Linq expression. On the other hand, you should initialise current with 1, same as in C#.

Furthermore, your “base case” is a bit weird; you can just write this:

result.Add(New T() { })

No need for the -1.

踏月而来 2024-11-17 03:50:31

我手头没有编译器来检查,但我会像这样转换它:

<Extension()>
Public Function Combinations(Of T)(elements As IEnumerable(Of T), k As Integer) As IEnumerable(Of T())

    Dim result As New List(Of T())()

    ' single combination
    If k = 0 Then
        result.Add(New T() {})
    Else
        Dim current As Integer = 1
        For Each element As T In elements
            'combine each element with k-1 combinations of subsequent elements
            result.AddRange(elements
                .Skip(PostfixInc(current))
                .Combinations(k - 1)
                .Select(Function(combination) (New T() { element }).Concat(combination).ToArray())
                )
        Next
    End If
    Return result

End Function

Private Function PostfixInc(ByRef value As Integer) As Integer

    Dim currentValue = value
    value += 1
    Return currentValue

End Function

这是我现在能想到的每个语法元素的直接转换。一旦你让它工作,然后考虑清理它(例如尝试消除 LINQ 表达式的副作用)。

编辑:

与您的代码的差异:

  • New T(-1) {} 应为 New T() {}
  • current 应初始化为 1 而不是 0。
  • Skip(current = current + 1) 不会执行您想要的操作。事实上,它什么也不做,因为 current = current + 1 是一个布尔表达式,其计算结果始终为 false。如果选项 strict 关闭,VB.NET 将默默地将 false 转换为 0;如果选项 strict 打开,则抛出编译器错误。

I don't have a compiler on hand to check, but I would convert it like this:

<Extension()>
Public Function Combinations(Of T)(elements As IEnumerable(Of T), k As Integer) As IEnumerable(Of T())

    Dim result As New List(Of T())()

    ' single combination
    If k = 0 Then
        result.Add(New T() {})
    Else
        Dim current As Integer = 1
        For Each element As T In elements
            'combine each element with k-1 combinations of subsequent elements
            result.AddRange(elements
                .Skip(PostfixInc(current))
                .Combinations(k - 1)
                .Select(Function(combination) (New T() { element }).Concat(combination).ToArray())
                )
        Next
    End If
    Return result

End Function

Private Function PostfixInc(ByRef value As Integer) As Integer

    Dim currentValue = value
    value += 1
    Return currentValue

End Function

That's as direct a conversion of each syntax element as I can think of right now. Once you have it working, then think about cleaning it up (e.g. try to remove side effects from the LINQ expression).

EDIT:

Differences from your code:

  • New T(-1) {} should be New T() {}.
  • current should be initialised to 1 not 0.
  • Skip(current = current + 1) will not do what you want. In fact, it does nothing, because current = current + 1 is a boolean expression that will always evaluate to false. VB.NET will silently convert false to 0 if option strict is off, or throw a compiler error if option strict is on.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文