syncing two lists with VBA

后端 未结 3 1597
时光取名叫无心
时光取名叫无心 2020-12-18 11:46

What is the best way to sync up two lists each of which may contain items not in the other? As shown the lists are not sorted - although if necessary sorting them first wou

相关标签:
3条回答
  • 2020-12-18 12:24

    Here's another option, this time using Dictionaries (add a reference to Microsoft Scripting Runtime, which also has several other hugely useful objects - don't start VBA coding without it!)

    As written, the output isn't sorted - that could be a bit of a showstopper. Anyway, there are a couple of nice little tricks here:

    Option Explicit
    
    Public Sub OutputLists()
    
    Dim list1, list2
    Dim dict1 As Dictionary, dict2 As Dictionary
    Dim ky
    Dim cel As Range
    
        Set dict1 = DictionaryFromArray(Array("a", "b", "c", "e"))
        Set dict2 = DictionaryFromArray(Array("b", "e", "c", "d"))
    
        Set cel = ActiveSheet.Range("A1")
    
        For Each ky In dict1.Keys
            PutRow cel, ky, True, dict2.Exists(ky)
            If dict2.Exists(ky) Then
                dict2.Remove ky
            End If
            Set cel = cel.Offset(1, 0)
        Next
    
        For Each ky In dict2
            PutRow cel, ky, False, True
            Set cel = cel.Offset(1, 0)
        Next
    
    End Sub
    
    Private Sub PutRow(cel As Range, val As Variant, in1 As Boolean, in2 As Boolean)
    
    Dim arr(1 To 2)
    
        If in1 Then arr(1) = val
        If in2 Then arr(2) = val
        cel.Resize(1, 2) = arr
    
    End Sub
    
    Private Function DictionaryFromArray(arr) As Dictionary
    
    Dim val
    
        Set DictionaryFromArray = New Dictionary
        For Each val In arr
            DictionaryFromArray.Add val, Nothing
        Next
    
    End Function
    
    0 讨论(0)
  • 2020-12-18 12:32

    Another option is Collections. This doesn't sort the output alphabetically, but you can sort the lists first if you need to. Note this will also give you a unique list,stripping out duplicates. The code assumes your lists are in string arrays L1 and L2.

    Dim C As New Collection,i As Long, j As Long
    ReDim LL(UBound(L1) + UBound(L2), 2) As String 'output array
    
    For i = 1 To UBound(L1)
      On Error Resume Next  'try adding to collection
        C.Add C.Count + 1, L1(i) 'store sequence number,ie 1,2,3,4,...
      On Error GoTo 0
      j = C(L1(i)) 'look up sequence number
      LL(j, 1) = L1(i)
    Next i
    
    For i = 1 To UBound(L2) 'same for L2
      On Error Resume Next
        C.Add C.Count + 1, L2(i)
      On Error GoTo 0
      j = C(L2(i))
      LL(j, 2) = L2(i)
    Next i
    
    'Result is in LL, number of rows is C.Count
    Range("Results").Resize(UBound(LL, 1), 2) = LL
    
    0 讨论(0)
  • 2020-12-18 12:34

    Here are some notes on using a disconnected recordset.

    Const adVarChar = 200  'the SQL datatype is varchar
    
    'Create arrays fron the lists
    asL1 = Split("a,b,c,", ",")
    asL2 = Split("b,e,c,d", ",")
    
    'Create a disconnected recordset
    Set rs = CreateObject("ADODB.RECORDSET")
    rs.Fields.append "Srt", adVarChar, 25
    rs.Fields.append "L1", adVarChar, 25
    rs.Fields.append "L2", adVarChar, 25
    
    rs.CursorType = adOpenStatic
    rs.Open
    
    'Add list 1 to the recordset
    For i = 0 To UBound(asL1)
        rs.AddNew Array("Srt", "L1"), Array(asL1(i), asL1(i))
        rs.Update
    Next
    
    'Add list 2
    For i = 0 To UBound(asL2)
        rs.MoveFirst
        rs.Find "L1='" & asL2(i) & "'"
    
        If rs.EOF Then
            rs.AddNew Array("Srt", "L2"), Array(asL2(i), asL2(i))
        Else
            rs.Fields("L2") = asL2(i)
        End If
    
        rs.Update
    Next
    
    rs.Sort = "Srt"
    
    'Add the data to the active sheet
    Set wks = Application.ActiveWorkbook.ActiveSheet
    
    rs.MoveFirst
    
    intRow = 1
    Do
        For intField = 1 To rs.Fields.Count - 1
            wks.Cells(intRow, intField + 1) = rs.Fields(intField).Value
        Next intField
    
        rs.MoveNext
        intRow = intRow + 1
    Loop Until rs.EOF = True
    
    0 讨论(0)
提交回复
热议问题