Преобразовать алгоритм из C # в VB.NET не удалось - PullRequest
4 голосов
/ 30 мая 2011

Я пытаюсь преобразовать следующий алгоритм из 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

Что-то не так, но я не уверен, что, я предполагаю, что проблема где-тов лямбде.

Кто-нибудь может указать, что я сделал неправильно с моим обращением?

Ответы [ 4 ]

2 голосов
/ 30 мая 2011

Использовать конвертер кодов ...

<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
0 голосов
/ 30 мая 2011

У меня нет компилятора для проверки, но я бы конвертировал его так:

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

EDIT:

Отличия от вашего кода:

  • New T(-1) {} должно быть New T() {}.
  • current следует инициализировать 1, а не 0.
  • Skip(current = current + 1) не будет делать то, что вы хотите. На самом деле, он ничего не делает, потому что current = current + 1 - это логическое выражение, которое всегда будет иметь значение false. VB.NET автоматически преобразует false в 0, если опция строгого режима отключена, или выдает ошибку компилятора, если опция строгого режима включена.
0 голосов
/ 30 мая 2011

Насколько я вижу, вообще нет необходимости увеличивать ток на месте.Просто увеличьте его после выражения Linq.С другой стороны, вы должны инициализировать current с 1, как в C #.

Кроме того, ваш «базовый случай» немного странный;Вы можете просто написать это:

result.Add(New T() { })

Нет необходимости в -1.

0 голосов
/ 30 мая 2011

Я вообще не эксперт по VB, но проблема может быть в следующем:

current = current + 1 - это не то же самое, что current++. Это (в основном) так же, как ++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.

...