Excel-VBA - Insert new first column in datafield array without loops or API calls

后端 未结 1 463
温柔的废话
温柔的废话 2020-11-22 13:33

Intro

Last year @PrzemyslawRemin posed the question how to add a counter column to an existing matrix in VBA without additional loops

相关标签:
1条回答
  • 2020-11-22 13:56

    Found solution via the Application.Index function

    I found a solution simply by trying out some unusual variations of the Application.Index function.

    Some peculiarities of the the Application.Index function

    Typically the index function would deliver a well defined item by its row and column position, but there are some not so widely known pecularities:

    1. Similarly to the Worksheet.Index function you can get the entire column or row items if the row or column number argument is set to zero (0).

    2. Use of array arguments possible - This function allows not only the known index indications by given numbers, but also array parameters to extract "rows" or "columns", so it's possible to indicate a wanted set of columns, e.g.A:C via Array(1,2,3) as column array argument.

    3. Filtering effects - Furthermore I learnt that it is possible to reduce the choice to some columns (rows) only, e.g. via Array(1,3) and even to change the internal order, e.g.Array(3,2,1)`.

    4. Restructuring - The most surprising fact, however, is that it is possible to repeat a column choice, e.g. via Array(1,1,2,3) or even Array(0,1,2,3) where the 0 item is the same as column 1. This can be used to reach the same effect as a column insertion.

    This last restructuring capability of the mentioned Index function is the key part of my approach:

    Code example

    Sub AddFirstIndexColumn()
      Dim v, i&, ws As Worksheet
      Set ws = ThisWorkbook.Worksheets("SourceSheet")  ' << change to source sheet name
    ' [1] get data
          v = ws.[A1:C5].Value2
    ' [2] define column array inserting first column (0 or 1) and preserving old values (1,2,3)
          v = Application.Index(v, _
              Application.Evaluate("row(1:" & UBound(v) & ")"), _
              Array(0, 1, 2, 3))   ' columns array where 0 reinserts the first column
    ' [3] add an current number in the first column
          For i = LBound(v) To UBound(v): v(i, 1) = i: Next i
     End Sub
    

    How to test the result

    Just insert the following to the code above:

    ' [4a] test result by debugging in immediate window
          For i = LBound(v) To UBound(v)
              Debug.Print "#" & i & ": " & Join(Application.Index(v, i, 0), ", ")
          Next i
    ' [4b] test result by writing back to target sheet
          Dim ws2 As Worksheet
          Set ws2 = ThisWorkbook.Worksheets("TargetSheet")  ' << change to target sheet name
          ws2.Range("A1").Resize(UBound(v), UBound(v, 2)).Offset(0, 0) = v
    

    Caveat

    The found solution seems to be restricted to 65536 rows (possibly similar to array transposing limitation), so that you can't use it for bigger data.

    Some recent Application.Index examples

    • Copy from sheet1 columns A,B,C,G,F,R,S,T to sheet2 in columns A,B,C,D,E,F,G,H
    • Multi criteria selection with VBA
    • How to join returned values from named range separated by comma
    0 讨论(0)
提交回复
热议问题