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

3

我如何将这些数组与 (2, 4, 5, 3, 7, 6) 的结果合并?

array1 = Array(4,5,3,7,6)

array2 = Array(2)

1
创建一个大小等于两个数组之和的空第三个数组,然后循环遍历每个数组,逐一添加其中的项。 - Scott Craner
FYI,我在 @ScottCraner 的评论中添加了一种替代方法,使用 Application.Index() 函数的高级功能来合并两个一维数组 :-) - T.M.
4个回答

7
你可以使用 Join() 方法将两个数组连接起来,然后再用 Split() 方法将结果分割成一个新的数组:
array3 = Split(Join(array2, ",") & "," & Join(array1, ","), ",")
说明:
Join() 函数将返回一个字符串,该字符串包含数组中的每个元素(第一个参数),由逗号(第二个参数)分隔。我们使用一个额外的逗号将这两个连接后的数组连接起来,以获得类似 2,4,5,3,7,6 的字符串。然后,我们使用 Split() 函数将该字符串转换回数组,并告诉 Split() 分隔符是逗号 ","

2
一个需要注意的地方是返回值将会是一个字符串,因此在检索值时可能需要进行其他处理。 - Scott Craner
1
Split() 的返回值将是一个数组,但是是的... JOIN() 的返回值将是一个字符串,如果一个元素包含正在使用的分隔符,则由 Split() 返回的数组将会很混乱。 - JNevill
4
Split 的返回值将是一个字符串数组。 - Scott Craner
1
啊!@ScottCraner 那是一个好的警告!这完全是hacky的,但你知道我喜欢一个好的hacky one-liner。 - JNevill
1
FYI,“你知道我喜欢一个好的hacky one-liner。” - 使用Application.Index()作为一行代码添加了另一种“连接两个数组”的解决方案,并保持数组值的原始类型(由于Index()结果是基于1的,因此需要进一步重新调整大小回到基于0的数组以保持原始设置)。 - T.M.

4
你可以使用ArrayList。如果需要,它还可以提供简单的排序。
Option Explicit
Public Sub test()
    Dim list1 As Object, list2 As Object

    Set list1 = CreateObject("System.Collections.Arraylist")
    Set list2 = CreateObject("System.Collections.Arraylist")
    list1.Add 4
    list1.Add 5
    list1.Add 3
    list1.Add 7
    list1.Add 6
    list2.Add 2
    list1.addRange list2
    list1.Sort
End Sub

添加了一种通过 ArrayLists “合并两个数组”的替代方案。:+) - T.M.
有趣的是:是否有一个类似于Join()的函数可以应用于ArrayList,例如Debug.Print Join(list1, "|")对象会导致错误13类型不匹配。 - T.M.
1
@T.M. 是的,你可以 > Join(list1.ToArray,"|") =) - JvdV

3

合并两个数组

作为Scott Craner提出的正确和有效的方法的替代方案,

创建一个大小为空的第三个数组,该数组大小为两个数组的总和,然后循环遍历每个数组,逐一添加项目。

... 我演示了一种方法,

  • 通过循环第二个数组中的元素插入到主数组中,而
  • 主数组只通过Application.Index()单行代码进行重构

由于此函数会将结果更改为基于1的数组,因此我将数组重新调整为基于0的数组。此外,我添加了一个可选的显示在VBE的即时窗口中,结果为2|4|5|3|7|6值:

第一步:与OP中相同的数组值的简单演示(插入1个元素)

Sub SimpleDemo()
'[0]declare and assign zero-based 1-dimensioned arrays
    Dim main, newTop
    main = Array(4, 5, 3, 7, 6)
    newTop = Array(2)              ' only one element in a first step
'[1]transform main array by inserting(/i.e. repeating) "another" 1st element
    main = Application.Index(main, Array(1, 1, 2, 3, 4, 5)) ' changes to 1-based 1-dim array
    ReDim Preserve main(0 To UBound(main) - 1)              ' back to zero-based 1-dim array
'[2]overwrite new first element by the 1st(only) element of newTop
    main(0) = newTop(0)
'[3](optional) display in VBE's Immediate Window: main(0 To 5) ~> 2|4|5|3|7|6
    Debug.Print "main(" & LBound(main) & " To " & UBound(main) & ") ~> " & _
                Join(main, "|")
End Sub

第二步:使用AddElem过程的更加通用方法

上面的演示仅插入了一个元素。因此,我编写了一个AddElem过程和一个帮助函数addedElems(),以允许插入更多元素。假设所有 1 维数组都是零基的,就像原始帖子中一样;顺便说一句,这很容易适应 :-)

Sub AddElem(main, newTop)
' Purp. : add/insert other array element(s) on top of zero-based main array
' Author: https://stackoverflow.com/users/6460297/t-m
' Date  : 2020-02-05
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' a)insert newTop element(s) on top of main array
    main = Application.Index(main, addedElems(main, newTop)) ' changes temporarily to 1-based mainay!
' b)make main array zero-based again (optional)
    ReDim Preserve main(0 To UBound(main) - 1)
' c)overwrite inserted starting element(s) by the newTop element(s)
    Dim i&: For i = 0 To UBound(newTop): main(i) = newTop(i): Next i
End Sub

帮助函数 addedElems()

Function addedElems(main, newTop) As Variant()
'Note : help function called by AddElem()
'Purp.: return ordinal element counters of combined arrays
    Dim i&, n&: n = UBound(main) + UBound(newTop) + 1
    ReDim tmp(0 To n)
    For i = 0 To UBound(newTop): tmp(i) = i: Next i
    For i = i To n: tmp(i) = i - UBound(newTop): Next i
    addedElems = tmp        ' return combined elem counters,  e.g. Array(1,2, 1,2,3,4,5)
End Function

示例调用

我稍微修改了OP的第二个数组的值(Array(2) ~> Array(20, 21)),以演示插入更多元素的结果,从而生成组合Array(20, 21, 2, 4, 5, 3, 7, 6)

Sub ExampleCall()
'[0]declare and assign zero-based 1-dimensional arrays
    Dim main, newTop
    main = Array(4, 5, 3, 7, 6)
    newTop = Array(20, 21)
'[1]Add/Insert newTop on top of main array
    AddElem main:=main, newTop:=newTop     ' or simply: AddElem main, newTop

'[2](optional) display in VBE's Immediate Window: ~~> main(0 To 6) ...20|21|4|5|3|7|6
    Debug.Print "main(" & LBound(main) & " To " & UBound(main) & ") ..." & _
                Join(main, "|")
End Sub

相关链接

同样地,您可以在此处学习有关在二维数组上应用 Application.Index() 函数的一些特殊性质,以便无需循环或 API 调用插入数据字段数组中的第一列。


1
赞同你详细的解释,顺便说一句,最近看到你对Application.Methods很感兴趣 =) - JvdV

2
晚来的派对客,但我也想加入讨论。
您可以简单地将两个数组中的一个复制到新数组中。然后使用Redim Preserve将其大小设置为两个原始数组的大小,以便仅循环第一个数组。以下代码很基本,但可以快速完成工作,而不需要转换任何数据类型:
Sub Test()

Dim arr1 As Variant: arr1 = Array(4, 5, 3, 7, 6)
Dim arr2 As Variant: arr2 = Array(2)
Dim arr3 As Variant: arr3 = arr2

ReDim Preserve arr3(UBound(arr1) + Ubound(arr2) + 1)
For x = (UBound(arr3) - UBound(arr1)) To UBound(arr3)
    arr3(x) = arr1(x - UBound(arr2) - 1)
Next x

End Sub

为了演示使用一些类型转换返回不同的数据类型:

要演示不同的Data Type的返回,需要进行一些Type转换:

Sub Test()

Dim arr1 As Variant: arr1 = Array(CDbl(4), CLng(5), CStr(3), CDate(7), CCur(6))
Dim arr2 As Variant: arr2 = Array(2)
Dim arr3 As Variant: arr3 = arr2

ReDim Preserve arr3(UBound(arr1) + Ubound(arr2) + 1)
For x = (UBound(arr3) - UBound(arr1)) To UBound(arr3)
    arr3(x) = arr1(x - UBound(arr2) - 1)
Next x

End Sub

enter image description here


2
另一种很有用的方法,展示了同样的思路,不需要通过循环逐个添加每个数组项 :+) - T.M.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接