1

In a process that I have developed the concatenation of 3 (2 dimension) arrays is taking approximately the 30% of the processing time in its current version. I have passed from a lot of different approaches for the task (e.g. typical concatenation with &, join function which is also slow etc). My current version of code is as follows:

    h1 = R21a: R11 = 0
    For k1 = 0 To i2
      For k2 = 0 To i1
        R11 = R11 + 1
        If A(k1, k2) = "1" Then Mid$(h1, R11, 1) = "1"
        If b1(k1, k2) = "1" Then Mid$(h1, R11 + R12a, 1) = "1"
        If b2(k1, k2) = "1" Then Mid$(h1, R11 + R13a, 1) = "1"
      Next
    Next

The use of Mid$ on the left of = has been proved to be the fastest approach, as I have initialized the string (h1) in its full length in the beginning of the code. My target is to concatenate all the 3 arrays in one string, one after the other. From my search in the web, seems that the fastest way is to use copymemory. But I could not find a way through this, as I am not experienced in API use. Any hint or page with practical guidance would be very helpful for me. Or, any other way to do it fast.

As I have not stopped to experiment, since I posted the above question a workaround came up and I want to share it. I could not believe that this workaround was so fast, so I have done some timing. The code as it is running now is as follows (both parts run one after the other in the same process):

    ' Existing solution.
    GTCs1 = GetTickCount()
      h1 = R21a: R11 = 0
      For k1 = 0 To i2: For k2 = 0 To i1: R11 = R11 + 1
        If A(k1, k2) = "1" Then Mid$(h1, R11, 1) = "1"
        If b1(k1, k2) = "1" Then Mid$(h1, R11 + R12a, 1) = "1"
        If b2(k1, k2) = "1" Then Mid$(h1, R11 + R13a, 1) = "1"
      Next: Next
    GTCf1 = GetTickCount(): GTCt1 = GTCt1 + (GTCf1 - GTCs1): GTCc1 = GTCc1 + 1

    ' Today's workaround ...
    GTCs2 = GetTickCount()
      Put #44, 1, A(): Get #44, 1, HshStr1
      Put #44, 2, b1(): Get #44, 2, HshStr2
      Put #44, 3, b2(): Get #44, 3, HshStr3: HshStr = HshStr1 & HshStr2 & HshStr3
    GTCf2 = GetTickCount(): GTCt2 = GTCt2 + (GTCf2 - GTCs2): GTCc2 = GTCc2 + 1

Timings for each part of the code is 0,0003526 for the existing solution and 0,0000855 for the workaround. Timings are averages of 100,000 repeats of the code and the workaround needs only 25% of the time that existing solution takes. So, "Put" can do concatenation of a string array without any difficulty. But, not to any array only for static ones. For dynamic arrays it is not the same. All the information is in VBA online documentation.

Demetres
  • 127
  • 2
  • 10

1 Answers1

1

CopyMemory allows you to copy a contiguous range of memory.

An Array in VBA is stored as a SAFEARRAY structure in memory.

A string (variable length, fixed length strings work differently) is stored as a BSTR structure in memory.

You also have functions such as VarPtr, StrPtr, and ObjPtr in VBA that can be used to obtain pointers for use with external APIs such as CopyMemory. StrPtr gets you a pointer to the actual buffer containing the string data of a string.

To give a more definitive answer we would need more information about your variables. You've not provided information such as WHAT the arrays are, if they are fixed length, variable length, variant arrays, typed arrays... You've also not provided information on what your destination string buffer h1 consists of. Is it a variable length string preallocated to the desired length or a fixed length string?

That said, there are only certain conditions under which this might work. If your array contains a series of characters, and each character is two bytes as they are in a BSTR, you may be able to copy contiguous regions from an array of these characters into a preallocated string using CopyMemory and speed your operation up. However if your array is an array of strings, this will not work. If it is an array of Variants this will not work.

Community
  • 1
  • 1
AndASM
  • 9,458
  • 1
  • 21
  • 33
  • All the 3 (2D) arrays are fixed strings of 1 character length, that is to say each element of the arrays contains 0 or 1. Destination string h1 is fixed string also with length=total length of the 3 arrays, initialized to 0's – Demetres Jan 21 '14 at 20:19
  • 2
    Assuming you are truely using an array of fixed length strings (eg `dim A() String * 1`). I added a new link at the bottom of the answer on howto get a pointer to the variable's data (that you can use in CopyMemory). However you'll have to do the math on your multiple dimensions, and possibly reorder the data depending if the linear order you want is the same or not as how the array stores it. I might try myself later, if I have time. I'll let you know if I do and update the answer accordingly. – AndASM Jan 22 '14 at 19:46