简体   繁体   中英

VBA only - Is there an easier way to concatenate array values based on their position?

I've had a little look and I've found similar questions but they all seem to be how to add one list to the end of another.

I've recently answered a question with a technique I use at work in Excel that relies on creating a 3rd column with a formula floodfill to concat col1 & col2 for each row. I figured there must be a better way to do this so had a little play in VBA and came up with the following from questions I could find. But now I have a couple of questions:

Is there a way to get rid of setting the 3rd array with x amount of arbitrary values which will just be replaced anyway? ReDim something maybe

Is there overall a better/neater way to combine elements from arr1 and arr2 based on their position without cycling through each one? (using in-built array commands or whatever)

(Apologies if this duplicates any thread somewhere, I did look, honest!)

Private Sub CommandButton1_Click()
Dim arr1() As Variant
Dim arr2() As Variant
Dim arr3() As Variant
Dim element As Variant
Dim pos As Integer

    arr1 = Array("ONE", "TWO", "THREE")
    arr2 = Array("1111", "2222", "3333")
    arr3 = Array("x", "x", "x")

    For Each element In arr1
        pos = Application.WorksheetFunction.Match(element, arr1, False) - 1
        arr3(pos) = arr1(pos) & arr2(pos)
        'MsgBox (arr1(pos) & arr2(pos) & arr3(pos))
    Next

    'Where arr3 will equal ("ONE1111", "TWO2222", "THREE3333")
End Sub

EDIT - Thanks all for the answers, giving me about 20 things to think about and play with over the next few days.

To expand on my comment, any code you might use for this WILL cycle through the array elements. The only difference with built-in code is you don't get to see the cycling code. Here is some code that allows you to make a simple function call and which supports any number of input arrays. The JoinArrayElements function does what you are asking, and you can use it without having to write the code to "cycle through the elements" each time.

Public Sub Main()
    Dim arr1, arr2
    arr1 = Array("ONE", "TWO", "THREE")
    arr2 = Array("1111", "2222", "3333")
    arr3 = Array("!@!@", "@#@#", "#$#$")

    Debug.Print arrayToString(joinArrayElements(arr1, arr2))
    Debug.Print arrayToString(joinArrayElements(arr1, arr2, arr3))
End Sub


Public Function arrayToString(arr As Variant) As String
    Dim output As String
    output = "["
    If UBound(arr) - LBound(arr) > 0 Then
        output = output & """" & arr(LBound(arr)) & """"
        For index = LBound(arr) + 1 To UBound(arr)
            output = output & ", " & """" & arr(index) & """"
        Next
    End If
    output = output & "]"
    arrayToString = output
End Function

Public Function joinArrayElements(ParamArray args() As Variant) As Variant
    'Validation to add:
    ' Are all the passed parameters actual valid arrays?
    ' Are they all the same length?

    Dim arrayNumber As Long
    Dim index As Long
    Dim arrOutput() As Variant

    ReDim arrOutput(LBound(args(0)) To UBound(args(0)))

    For arrayNumber = LBound(args) To UBound(args)
        For index = LBound(args(0)) To UBound(args(0))
            arrOutput(index) = arrOutput(index) & args(arrayNumber)(index)
        Next
    Next

    joinArrayElements = arrOutput
End Function

The output of this code is:

["ONE1111", "TWO2222", "THREE3333"]

["ONE1111!@!@", "TWO2222@#@#", "THREE3333#$#$"]

If you don't need to keep arr1 in its original form then:

arr1 = Array("ONE", "TWO", "THREE")
arr2 = Array("1111", "2222", "3333")


For x =lbound(arr1) to ubound(arr1)
    arr1(x) = arr1(x) & arr2(x)
Next

There are few useful built-in array functions/methods in VBA, but looping isn't necessarily a bad thing.

You could always do something like this, but it may not scale well and is a worse approach I think:

Dim r, arr1, arr2

arr1 = Array("ONE", "TWO", "THREE")
arr2 = Array("1111", "2222", "3333")

r = ActiveSheet.Evaluate("={""" & Join(arr1, """,""") & """} & {""" & _
                                  Join(arr2, """,""") & """}")

Debug.Print Join(r, ",") '>> ONE1111,TWO2222,THREE3333

Here is how you would ReDim the array. The first time you size the array use ReDim array(size) and after that you'll use ReDim Preserve array(size) to preserve the information already in the array.

在此处输入图片说明

Private Sub CommandButton1_Click()
    Dim arr1() As Variant, arr2() As Variant, arr3() As Variant
    Dim pos As Integer

    arr1 = Array("ONE", "TWO", "THREE")
    arr2 = Array("1111", "2222", "3333")

    ReDim arr3(pos)

    For pos = 0 To UBound(arr1)
        ReDim Preserve arr3(pos)
        arr3(pos) = arr1(pos) & arr2(pos)
    Next
End Sub

You may look at just using UDTs instead.

Public Type Car
    Manufacturer As String
    Model As String
    Price As Currency
    Doors As Integer
    Manufactured As Date
End Type

Dim myCars(0 To 2) as Car

myCars(0).Manufacturer="Toyota"
myCars(0).Model="86"

myCars(1).Manufacturer="Mazda"
myCars(1).Model="MX5"

'Then you can just use the fields together when needed like...
msgbox myCars(0).Manufacturer & " " & myCars(0).Model
msgbox myCars(1).Manufacturer & " " & myCars(1).Model

'Or even a function to return..
Public Function CarInfo(intCarID as Integer)

CarInfo = myCars(intCarID).Manufacturer & " " & myCars(intCarID).Model

End function

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM