如何在 VBA 中合并两个数组?

问题描述 投票:0回答:18

给予

Dim arr1 As Variant
Dim arr2 As Variant
Dim arr3 As Variant

arr1 = Array("A", 1, "B", 2)
arr2 = Array("C", 3, "D", 4)

问题

我可以对

arr1
arr2
执行什么样的操作并将结果分配给
arr3
得到类似的结果:

arr3 = ("A", "C", 1, 3, "B", "D", 2, 4)

提示(由于注释):“1)

arr1
中的元素是名称,
arr2
中的元素是值,
arr3
中的最终元素实际上是名称-值对,因此只要它们是配对后我不会关心它们是否按顺序排列。”

arrays vba vb6 merge
18个回答
23
投票

试试这个:

arr3 = Split(Join(arr1, ",") & "," & Join(arr2, ","), ",") 

13
投票

不幸的是,VB6 中的数组类型没有那么多令人惊叹的功能。您几乎只需迭代数组并将它们手动插入到第三个

假设两个数组的长度相同

Dim arr1() As Variant
Dim arr2() As Variant
Dim arr3() As Variant

arr1() = Array("A", 1, "B", 2)
arr2() = Array("C", 3, "D", 4)

ReDim arr3(UBound(arr1) + UBound(arr2) + 1)

Dim i As Integer
For i = 0 To UBound(arr1)
    arr3(i * 2) = arr1(i)
    arr3(i * 2 + 1) = arr2(i)
Next i

更新:修复了代码。对之前的错误版本感到抱歉。我花了几分钟才访问 VB6 编译器来检查它。


4
投票

此函数将按照 JohnFx 的建议进行操作,并允许数组具有不同的长度

Function mergeArrays(ByVal arr1 As Variant, ByVal arr2 As Variant) As Variant
    Dim holdarr As Variant
    Dim ub1 As Long
    Dim ub2 As Long
    Dim bi As Long
    Dim i As Long
    Dim newind As Long

        ub1 = UBound(arr1) + 1
        ub2 = UBound(arr2) + 1

        bi = IIf(ub1 >= ub2, ub1, ub2)

        ReDim holdarr(ub1 + ub2 - 1)

        For i = 0 To bi
            If i < ub1 Then
                holdarr(newind) = arr1(i)
                newind = newind + 1
            End If

            If i < ub2 Then
                holdarr(newind) = arr2(i)
                newind = newind + 1
            End If
        Next i

        mergeArrays = holdarr
End Function

4
投票

我尝试了上面提供的代码,但它给了我错误 9。 我编写了这段代码,它对于我的目的来说工作得很好。 我希望其他人也觉得它有用。

Function mergeArrays(ByRef arr1() As Variant, arr2() As Variant) As Variant

    Dim returnThis() As Variant
    Dim len1 As Integer, len2 As Integer, lenRe As Integer, counter As Integer
    len1 = UBound(arr1)
    len2 = UBound(arr2)
    lenRe = len1 + len2
    ReDim returnThis(1 To lenRe)
    counter = 1

    Do While counter <= len1 'get first array in returnThis
        returnThis(counter) = arr1(counter)
        counter = counter + 1
    Loop
    Do While counter <= lenRe 'get the second array in returnThis
        returnThis(counter) = arr2(counter - len1)
        counter = counter + 1
    Loop

mergeArrays = returnThis
End Function

2
投票

如果 Lbound 不为 0 或 1,则有效。您在开始时 Redim 一次

Function MergeArrays(ByRef arr1 As Variant, ByRef arr2 As Variant) As Variant

'Test if not isarray then exit
If Not IsArray(arr1) And Not IsArray(arr2) Then Exit Function

Dim arr As Variant
Dim a As Long, b As Long 'index Array
Dim len1 As Long, len2 As Long 'nb of item

'get len if array don't start to 0
len1 = UBound(arr1) - LBound(arr1) + 1
len2 = UBound(arr2) - LBound(arr2) + 1

b = 1 'position of start index
'dim new array
ReDim arr(b To len1 + len2)
'merge arr1
For a = LBound(arr1) To UBound(arr1)
    arr(b) = arr1(a)       
    b = b + 1 'move index
Next a
'merge arr2
For a = LBound(arr2) To UBound(arr2)
    arr(b) = arr2(a)
    b = b + 1 'move index
Next a

'final
MergeArrays = arr

End Function

2
投票

我想采用 user3286479 的好主意来处理来自单列范围的数组:

Dim ws As Worksheet
Set ws = ActiveSheet
arr1 = ws.Range("A2:A10").Value2
arr2 = ws.Range("B2:B6").Value2
    
arr3 = Split(Join(Application.Transpose(arr1), ",") & "," & Join(Application.Transpose(arr2), ","), ",")

1
投票

我喜欢的方法有点长,但比其他答案有一些优点:

  • 它可以一次组合无限数量的数组
  • 它可以将数组与非数组(对象、字符串、整数等)组合
  • 它解释了一个或多个数组可能包含对象的可能性
  • 它允许用户选择新数组的基数(0、1等)

这是:

Function combineArrays(ByVal toCombine As Variant, Optional ByVal newBase As Long = 1)
'Combines an array of one or more 1d arrays, objects, or values into a single 1d array
'newBase parameter indicates start position of new array (0, 1, etc.)
'Example usage:
    'combineArrays(Array(Array(1,2,3),Array(4,5,6),Array(7,8))) -> Array(1,2,3,4,5,6,7,8)
    'combineArrays(Array("Cat",Array(2,3,4))) -> Array("Cat",2,3,4)
    'combineArrays(Array("Cat",ActiveSheet)) -> Array("Cat",ActiveSheet)
    'combineArrays(Array(ThisWorkbook)) -> Array(ThisWorkbook)
    'combineArrays("Cat") -> Array("Cat")

    Dim tempObj As Object
    Dim tempVal As Variant

    If Not IsArray(toCombine) Then
        If IsObject(toCombine) Then
            Set tempObj = toCombine
            ReDim toCombine(newBase To newBase)
            Set toCombine(newBase) = tempObj
        Else
            tempVal = toCombine
            ReDim toCombine(newBase To newBase)
            toCombine(newBase) = tempVal
        End If
        combineArrays = toCombine
        Exit Function
    End If

    Dim i As Long
    Dim tempArr As Variant
    Dim newMax As Long
    newMax = 0

    For i = LBound(toCombine) To UBound(toCombine)
        If Not IsArray(toCombine(i)) Then
            If IsObject(toCombine(i)) Then
                Set tempObj = toCombine(i)
                ReDim tempArr(1 To 1)
                Set tempArr(1) = tempObj
                toCombine(i) = tempArr
            Else
                tempVal = toCombine(i)
                ReDim tempArr(1 To 1)
                tempArr(1) = tempVal
                toCombine(i) = tempArr
            End If
            newMax = newMax + 1
        Else
            newMax = newMax + (UBound(toCombine(i)) + LBound(toCombine(i)) - 1)
        End If
    Next
    newMax = newMax + (newBase - 1)

    ReDim newArr(newBase To newMax)
    i = newBase
    Dim j As Long
    Dim k As Long
    For j = LBound(toCombine) To UBound(toCombine)
        For k = LBound(toCombine(j)) To UBound(toCombine(j))
            If IsObject(toCombine(j)(k)) Then
                Set newArr(i) = toCombine(j)(k)
            Else
                newArr(i) = toCombine(j)(k)
            End If
            i = i + 1
        Next
    Next

    combineArrays = newArr

End Function

1
投票

不幸的是,如果不逐个元素地执行,就无法使用 VBA 在数组中追加/合并/插入/删除元素,这与许多现代语言(如

Java
Javascript
)不同。

可以使用

split
join
来做到这一点,就像之前的答案所示,但这是一种缓慢的方法,而且不通用。

为了我个人的使用,我为一维数组实现了

splice
函数,类似于 Javascript 或 Java。
splice
获取一个数组,并可以选择从给定位置删除一些元素,还可以选择在该位置插入一个数组

'*************************************************************
'*                      Fill(N1,N2)
'* Create 1 dimension array with values from N1 to N2 step 1
'*************************************************************
Function Fill(N1 As Long, N2 As Long) As Variant
Dim Arr As Variant
If N2 < N1 Then
  Fill = False
  Exit Function
End If
Fill = WorksheetFunction.Transpose(
          Evaluate("Row(" & N1 & ":" & N2 & ")"))
End Function
'**********************************************************************
'*                        Slice(AArray, [N1,N2])
'* Slice an array between indices N1 to N2
'***********************************************************************
Function Slice(VArray As Variant, Optional N1 As Long = 1, 
               Optional N2 As Long = 0) As Variant
Dim Indices As Variant
If N2 = 0 Then N2 = UBound(VArray)
If N1 = LBound(VArray) And N2 = UBound(VArray) Then
   Slice = VArray
Else
  Indices = Fill(N1, N2)
  Slice = WorksheetFunction.Index(VArray, 1, Indices)
End If
End Function
'************************************************
'*                 AddArr(V1,V2, [V3])
'* Concatena 2 ou 3 vetores
'**************************************************
Function AddArr(V1 As Variant, V2 As Variant, 
  Optional V3 As Variant = 0, Optional Sep = "#") As Variant
Dim Arr As Variant
Dim Ini As Integer
Dim N As Long, K As Long, I As Integer
  Arr = V1
  Ini = UBound(Arr)
  N = UBound(V1) - LBound(V1) + 1 + UBound(V2) - LBound(V2) + 1
  ReDim Preserve Arr(N)
  K = 0
  For I = LBound(V2) To UBound(V2)
    K = K + 1
    Arr(Ini + K) = V2(I)
  Next I
If IsArray(V3) Then
  Ini = UBound(Arr)
  N = UBound(Arr) - LBound(Arr) + 1 + UBound(V3) - LBound(V3) + 1
  ReDim Preserve Arr(N)
  K = 0
  For I = LBound(V3) To UBound(V3)
    K = K + 1
    Arr(Ini + K) = V3(I)
  Next I
End If
AddArr = Arr
End Function

'**********************************************************************
'*                        Slice(AArray,Ind, [ NElme, Vet] )
'* Delete NELEM (default 0) element from position IND in VARRAY
'* and optionally insert an array VET in that postion
'***********************************************************************
Function Splice(VArray As Variant, Ind As Long, 
  Optional NElem As Long = 0, Optional Vet As Variant = 0) As Variant
Dim V1, V2
If Ind < LBound(VArray) Or Ind > UBound(VArray) Or NElem < 0 Then
  Splice = False
  Exit Function
End If
V2 = Slice(VArray, Ind + NElem, UBound(VArray))
If Ind > LBound(VArray) Then
  V1 = Slice(VArray, LBound(VArray), Ind - 1)
  If IsArray(Vet) Then
     Splice = AddArr(V1, Vet, V2)
  Else
     Splice = AddArr(V1, V2)
  End If
Else
  If IsArray(Vet) Then
     Splice = AddArr(Vet, V2)
  Else
     Splice = V2
  End If
End If

End Function

用于测试

Sub TestSplice()
Dim V, Res
Dim J As Integer
V = Fill(100, 109)
Res = Splice(V, 2, 2, Array(201, 202))
PrintArr (Res)
End Sub

'************************************************
'*                 PrintArr(VArr)
'* Print the array VARR
'**************************************************
Function PrintArr(VArray As Variant)
Dim S As String
S = Join(VArray, ", ")
MsgBox (S)
End Function

结果

100,201,202,103,104,105,106,107,108,109

1
投票

遵循@johannes解决方案,但合并时不会丢失数据(缺少第一个元素):

    Function mergeArrays(ByRef arr1() As Variant, arr2() As Variant) As Variant

    Dim returnThis() As Variant
    Dim len1 As Integer, len2 As Integer, lenRe As Integer, counter As Integer
    len1 = UBound(arr1)
    len2 = UBound(arr2)
    lenRe = len1 + len2 + 1
    ReDim returnThis(0 To lenRe)
    counter = 0

    For counter = 0 To len1 'get first array in returnThis
        returnThis(counter) = arr1(counter)
    Next


    For counter = 0 To len2 'get the second array in returnThis
        returnThis(counter + len1 + 1) = arr2(counter)
    Next
mergeArrays = returnThis
End Function

1
投票

要连接 Array1 和 Array2,请创建一个新数组,例如 JointArray

Dim JointArray As Variant
ReDim JointArray(UBound(Array1) + UBound(Array2) + 1) As Variant
For i = 0 To UBound(JointArray)
    If i <= UBound(Array1) Then
    JointArray(i) = Array1(i)
    Else
    JointArray(i) = Array2(i - UBound(Array1) - 1)
    End If
Next

0
投票

这是一个使用集合对象来组合两个一维数组并传递它们的版本 到第三个数组。不适用于多维数组。

Function joinArrays(arr1 As Variant, arr2 As Variant) As Variant
 Dim arrToReturn() As Variant, myCollection As New Collection
 For Each x In arr1: myCollection.Add x: Next
 For Each y In arr2: myCollection.Add y: Next

 ReDim arrToReturn(1 To myCollection.Count)
 For i = 1 To myCollection.Count: arrToReturn(i) = myCollection.Item(i): Next
 joinArrays = arrToReturn
End Function

0
投票
Function marr(arr1 As Variant, arr2 As Variant) As Variant
Dim item As Variant
    For Each item In arr1
        i = i + 1
    Next item
    For Each item In arr2
        i = i + 1
    Next item
ReDim MergeData(0 To i)
i = 1
    For Each item In arr1
        MergeData(i) = item
        i = i + 1
    Next item
    For Each item In arr2
        MergeData(i) = item
        i = i + 1
    Next item
    marr = MergeData
End Function

0
投票

甚至是变量可以未初始化、空数组或对象数组(例如 Dictionary 对象)的方式。不过,一次只能处理一个维度。此外,它将 arr2 附加到 arr1,而不是合并。

Function appendArray(ByVal arr1 As Variant, ByVal arr2 As Variant) As Variant
    Dim holdarr As Variant
    Dim ub1 As Long
    Dim ub2 As Long
    Dim i As Long
    Dim newind As Long

                            ' Allows for one or both variants to not be arrays
    If IsEmpty(arr1) Or Not IsArray(arr1) Then
        arr1 = Array()
    End If

    If IsEmpty(arr2) Or Not IsArray(arr2) Then
        arr2 = Array()
    End If
                            ' Now we assume we DO have two ARRAYS, even if one or the other
                            ' has no elements
    ub1 = UBound(arr1)
    ub2 = UBound(arr2)

    If ub1 = -1 Then
        appendArray = arr2
        Exit Function
    End If

    If ub2 = -1 Then
        appendArray = arr1
        Exit Function
    End If

            ' Copy the first array. We know it is not empty.
    holdarr = arr1

            ' Grow it to the final size we need, keeping the current contents
    ReDim Preserve holdarr(ub1 + ub2 + 1)

            ' Set the starting new index
    newind = UBound(arr1) + 1

            ' Append the second array, allowing that it might be an array of objects
    For i = 0 To ub2
        If VarType(arr2(i)) = vbObject Then
            Set holdarr(newind) = arr2(i)
        Else
            holdarr(newind) = arr2(i)
        End If
        newind = newind + 1
    Next i
            ' Return the appended array
    appendArray = holdarr
End Function

0
投票

我真的很欣赏 Buggabil 和 Daniel McCracken 的回应。 我需要一个函数来组合多维数组,但我确信我将来会使用 Daniel 的。 我对 Buggabil 进行了一些修改,以 1) 容纳混合有变量和对象的多维数组,2) 按顺序合并两个数组而不是网格在一起(因为两个数组在 For 循环的每个步骤中组合在一起)。 有关说明,请参阅下面的“过去/现在”示例。

Function mergeArrays(ByVal arr1 As Variant, ByVal arr2 As Variant) As Variant
'Appends arr2 to arr1.
'Ex: mergeArrays(Array(0,1,2,3),Array(4,5,6,7)) = Array(0,1,2,3,4,5,6,7)
'Was: mergeArrays(Array(0,1,2), Array(Array(4, Object5, Object6), _
                                      Array(7, Object8, Object9)) = _
      = Array(Array(0,1,2),4,7,Object5,Object8,Object6,Object9)
'Now: = Array(Array(0,1,2), _
              Array(4, Object5, Object6), _
              Array(7, Object8, Object9))

'Source: Buggabill, https://stackoverflow.com/questions/1588913/how-do-i-merge-two-arrays-in-vba
    
    Dim holdarr As Variant, ub1 As Long, ub2 As Long, bi As Long, i As Long, newind As Long

    ub1 = UBound(arr1) + 1 
    ub2 = UBound(arr2) + 1

    bi = IIf(ub1 >= ub2, ub1, ub2)

    ReDim holdarr(ub1 + ub2 - 1)

    For i = 0 To bi
        If i < ub1 Then
            If IsObject(arr1(i)) Then
                Set holdarr(newind) = arr1(i)
            Else
                holdarr(newind) = arr1(i)
            End If
            newind = newind + 1
        ElseIf i < ub2 + ub1 Then
            If IsObject(arr2(i - ub1)) Then
                Set holdarr(newind) = arr2(i - ub1)
            Else
                holdarr(newind) = arr2(i - ub1)
            End If
            newind = newind + 1
        End If
    Next i
    
    mergeArrays = holdarr
End Function

希望这对你们有些人有帮助。


0
投票

使用 Split

 函数扩展 
ArrayToText()
 方法
(MS365)

如果您处理 MS/Excel 365,您可以通过传递所谓的 锯齿数组 (又称为数组的数组) 作为主要参数来简化连接和拆分 (请参阅 @user3286479 最受支持的 post 。这个锯齿状阵列可能包括两个甚至更多阵列,而不仅仅是arr1

arr2

作为进一步的好处,我提供了决定数组是否返回合并的数组元素

连续(默认值additive=True

)或不返回(即与显式参数交织在一起
additive=False
)的选项。

Function MergeArr(jagged As Variant, _ Optional ByVal additive As Boolean = True) 'Note: returns only string elements (needs arrays of same length) If additive Then ' all elems of 1st array, then all elems of 2nd one etc. MergeArr = Split(Application.ArrayToText(jagged), ", ") Else ' intertwine first elems of each array, then all second elems etc. MergeArr = Split(Application.ArrayToText(Application.Transpose(jagged)), ", ") End If End Function

调用示例

Sub testMergeArr() Dim arr1 As Variant arr1 = Array("A", 1, "B", 2) Dim arr2 As Variant arr2 = Array("C", 3, "D", 4) Dim arr3 As Variant arr3 = MergeArr(Array(arr1, arr2)) Debug.Print "additive ~~> " & Application.ArrayToText(arr3) arr3 = MergeArr(Array(arr1, arr2), False) Debug.Print "alternating ~~> " & Application.ArrayToText(arr3) End Sub

结果出现在 VB 编辑器的即时窗口中

additive ~~> A, 1, B, 2, C, 3, D, 4 alternating ~~> A, C, 1, 3, B, D, 2, 4

注意事项

上述方法的一个可能的缺点是所有元素都将作为字符串返回,因此也包括所有数值。为了

避免这种情况,您可以使用以下函数或者使用FilterXML()

(顺便说一句,自2013年起可用):

Function MergeArrXML(jagged As Variant, _ Optional ByVal additive As Boolean = True) 'Note: allows to maintain not only string elements, but also numeric values (doubles) Dim content As String If additive Then ' all elems of 1st array, then all elems of 2nd one etc. content = Replace(Application.ArrayToText(jagged), ", ", "</i><i>") Else ' intertwine first elems of each array, then all second elems etc. content = Replace(Application.ArrayToText(Application.Transpose(jagged)), ", ", "</i><i>") End If MergeArrXML = Application.Transpose(Application.FilterXML("<r><i>" & content & "</i></r>", "//i")) End Function
    

0
投票
Sub MergeArraysTest() Dim I As Long Dim Arr1(3) As Double Dim Arr2(5) As Double Dim MrgArr() As Double Arr1(0) = 123.456 Arr1(1) = 123.456 Arr1(2) = 123.456 Arr1(3) = 123.456 Arr2(0) = 789.101112 Arr2(1) = 789.101112 Arr2(2) = 789.101112 Arr2(3) = 789.101112 Arr2(4) = 789.101112 Arr2(5) = 789.101112 MrgArr = MergeArraysDataTypeDouble(Arr1, Arr2) For I = LBound(MrgArr) To UBound(MrgArr) Step 1 Debug.Print "***" & MrgArr(I) & "***" Next End Sub
    Public Function MergeArraysDataTypeDouble(Array1() As Double, Array2() As Double) As Double()

        Dim I As Long
        Dim J As Long
        Dim MergedArray() As Double
        ReDim MergedArray(UBound(Array1) + UBound(Array2) + 1)

        For I = LBound(MergedArray) To UBound(MergedArray) Step 1
            If I <= UBound(Array1) Then
                MergedArray(I) = Array1(I)
            ElseIf I > UBound(Array1) Then
                MergedArray(I) = Array2(J)
                J = J + 1
            End If
        Next
        MergeArraysDataTypeDouble = MergedArray

    End Function
    

0
投票
这是我的版本。

    任意长度
  • 任何数据类型
  • 浅复制,但适用于 Array() 元素
Sub ArrayCat(ByRef arr1, ByRef arr2) Dim newLen As Integer, idx1 As Integer, idx2 As Integer idx1 = UBound(arr1) + 1 newLen = UBound(arr1) + UBound(arr2) + 1 ReDim Preserve arr1(newLen) idx2 = 0 For idx1 = idx1 To newLen arr1(idx1) = arr2(idx2) idx2 = idx2 + 1 Next idx1 End Sub
    

0
投票
这是我提出的在 VBA 中组合多个一维数组的解决方案。

Public Function CombineArrays(ByVal ArrayList As Variant) As Variant '--------------------------------------------------------------------------------------- ' Procedure : CombineArrays ' Author : Adiv Abramson ' Date : 09/25/2024 ' Purpose : Combine multiple 1D arrays. ' : Nested arrays are not supported. ' : ' : ' : ' : ' : ' : ' : ' : ' : ' : ' : ' Versions : 1.0 - 09/25/2024 - Adiv Abramson ' : ' : ' : ' : ' : ' : '--------------------------------------------------------------------------------------- 'Strings: '********************************* '********************************* 'Numerics: '********************************* Dim lngSubArraySize As Long Dim lngCombinedArraySize As Long Dim lngCombinedArrayIndex As Long '********************************* 'Worksheets: '********************************* '********************************* 'Workbooks: '********************************* '********************************* 'Ranges: '********************************* '********************************* 'Arrays: '********************************* Dim arCombined() As Variant '********************************* 'Objects: '********************************* '********************************* 'Variants: '********************************* Dim vntSubArray As Variant Dim vntSubArrayElement As Variant '********************************* 'Booleans: '********************************* '********************************* 'Constants '********************************* '********************************* 10 On Error GoTo ErrProc 20 CombineArrays = Null '======================================================== 'Validate input 'ArrayList must contain at least 2 arrays. '======================================================== 30 If Not IsArray(ArrayList) Then Exit Function 40 If GetUBound(ArrayList) < 1 Then Exit Function 50 lngCombinedArraySize = -1 60 For Each vntSubArray In ArrayList 70 If Not IsArray(vntSubArray) Then Exit Function 80 lngSubArraySize = GetUBound(vntSubArray) 90 If lngSubArraySize = -1 Then Exit Function '======================================================== 'Use the number of elements in each subarray, which is 'the UBound + 1 and add that to the size of the 'combined array to be created. '======================================================== 100 lngCombinedArraySize = lngCombinedArraySize + lngSubArraySize + 1 110 Next vntSubArray 120 ReDim arCombined(lngCombinedArraySize) '======================================================== 'Populate array combining elements of all the sub arrays. '======================================================== 130 lngCombinedArrayIndex = 0 140 For Each vntSubArray In ArrayList 150 For Each vntSubArrayElement In vntSubArray 160 arCombined(lngCombinedArrayIndex) = vntSubArrayElement 170 lngCombinedArrayIndex = lngCombinedArrayIndex + 1 180 Next vntSubArrayElement 190 Next vntSubArray 200 CombineArrays = arCombined 210 Exit Function ErrProc: 220 CombineArrays = Null 230 MsgBox "Error " & Err.Number & " (" & Err.Description & ") at line " _ & Erl & " in procedure CombineArrays of Module " & MODULE_NAME End Function
    
© www.soinside.com 2019 - 2024. All rights reserved.