How to Generate Combinations of Elements of a List in .NET 4.0

后端 未结 5 1505
小鲜肉
小鲜肉 2020-12-01 13:07

I have a question that is similar, but not identical, to the one answered here.

I would like a function generate all of the k-combinations of elements from

5条回答
  •  感动是毒
    2020-12-01 13:43

    I tried creating an enumerable that can accomplish this task in VB. This is the result:

    Public Class CombinationEnumerable(Of T)
    Implements IEnumerable(Of List(Of T))
    
    Private m_Enumerator As CombinationEnumerator
    
    Public Sub New(ByVal values As List(Of T), ByVal length As Integer)
        m_Enumerator = New CombinationEnumerator(values, length)
    End Sub
    
    Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of List(Of T)) Implements System.Collections.Generic.IEnumerable(Of List(Of T)).GetEnumerator
        Return m_Enumerator
    End Function
    
    Private Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
        Return m_Enumerator
    End Function
    
    Private Class CombinationEnumerator
        Implements IEnumerator(Of List(Of T))
    
        Private ReadOnly m_List As List(Of T)
        Private ReadOnly m_Length As Integer
    
        ''//The positions that form the current combination
        Private m_Positions As List(Of Integer)
    
        ''//The index in m_Positions that we are currently moving
        Private m_CurrentIndex As Integer
    
        Private m_Finished As Boolean
    
    
        Public Sub New(ByVal list As List(Of T), ByVal length As Integer)
            m_List = New List(Of T)(list)
            m_Length = length
        End Sub
    
        Public ReadOnly Property Current() As List(Of T) Implements System.Collections.Generic.IEnumerator(Of List(Of T)).Current
            Get
                If m_Finished Then
                    Return Nothing
                End If
                Dim combination As New List(Of T)
                For Each position In m_Positions
                    combination.Add(m_List(position))
                Next
                Return combination
            End Get
        End Property
    
        Private ReadOnly Property Current1() 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
    
            If m_Positions Is Nothing Then
                Reset()
                Return True
            End If
    
            While m_CurrentIndex > -1 AndAlso (Not IsFree(m_Positions(m_CurrentIndex) + 1)) _
                ''//Decrement index of the position we're moving
                m_CurrentIndex -= 1
            End While
    
            If m_CurrentIndex = -1 Then
                ''//We have finished
                m_Finished = True
                Return False
            End If
            ''//Increment the position of the last index that we can move
            m_Positions(m_CurrentIndex) += 1
            ''//Add next positions just after it
            Dim newPosition As Integer = m_Positions(m_CurrentIndex) + 1
            For i As Integer = m_CurrentIndex + 1 To m_Positions.Count - 1
                m_Positions(i) = newPosition
                newPosition += 1
            Next
            m_CurrentIndex = m_Positions.Count - 1
            Return True
        End Function
    
        Public Sub Reset() Implements System.Collections.IEnumerator.Reset
            m_Finished = False
            m_Positions = New List(Of Integer)
            For i As Integer = 0 To m_Length - 1
                m_Positions.Add(i)
            Next
            m_CurrentIndex = m_Length - 1
        End Sub
    
        Private Function IsFree(ByVal position As Integer) As Boolean
            If position < 0 OrElse position >= m_List.Count Then
                Return False
            End If
            Return Not m_Positions.Contains(position)
        End Function
    
        ''//Add IDisposable support here
    
    
    End Class
    
    End Class
    

    ...and you can use my code this way:

    Dim list As New List(Of Integer)(...)
    Dim iterator As New CombinationEnumerable(Of Integer)(list, 3)
        For Each combination In iterator
            Console.WriteLine(String.Join(", ", combination.Select(Function(el) el.ToString).ToArray))
        Next
    

    My code gives combinations of a specified length (3 in my example) though, I just realized that you wish to have combinations of any length (I think), but it's a good start.

提交回复
热议问题