2
\$\begingroup\$

Project

I have created a VBA module calledIdx which you may findhere on GitHub. It is inspired bypluck() andchuck() inR, whose purpose is

to index deeply and flexibly into data structures.

It takes a set of indices and extracts the corresponding element from an arbitrary data structure. Indices may be numeric positions and textual keys, which you may supply as separate arguments or within a single array.

The data structure may be an array of any dimensionality, or aCollection, or aDictionary…or even a deep nesting ofall such structures. The only requirement is that thex(i) syntax applies at every level, like arrays or objects with adefault member.


For your convenience, this post is broken down into four further sections:

  • API for available features.
  • Approach for details on implementation.
  • Questions for specific issues where I desire advice.
  • Code for the actualsource code.

API

Here are the functions exposed byIdx, which are usable in VBA and (often) Excel. Here is aParamArray where you supply indices as separate arguments.

' ######################' ## Array Extraction ##' ######################' Supply indices programmatically.Arr_Index(arr, indices)' ##########################' ## Arbitrary Extraction ##' ##########################' Supply indices programmatically...Index(x, indices)' ...and manually.Index0(x, …)' ###############' ## Utilities ##' ###############' Assign any value to a variableAssign var, val' Count the dimensions in an array.Arr_Rank(arr)' Measure an array along a dimension.Arr_Length(arr, [dimension])

Approach

Array Extraction

TheArr_Index() function lets you access arrays of any dimensionality, using an array of positional indices:

Dim arr(1 To 2, 3 To 4, 5 To 6) As String' ...Arr_Index(arr, Array(2, 4, 5))

It does so by implementing apyramid which handles every dimensionality, from one dimension throughsixty dimensions. Seehere for source code.

    Case  1: Assign v, a(i(l))    Case  2: Assign v, a(i(l),i(l+1))    Case  3: Assign v, a(i(l),i(l+1),i(l+2))    ' ...    Case 60: Assign v, a(i(l),i(l+1),i(l+2),…,i(l+59))

Arbitrary Extraction

TheIndex() function lets you access any structure whatsoever, using an array of keyed or positional indices:

Dim clx As Collectionclx.Add arr, key := "3D Array"Index(clx,          1, 2, 4, 5)Index(clx, "3D Array", 2, 4, 5)

It does so with a recursive algorithm:

  • If the inputx is an object or a unidimensional array, we simply use the first index to extractv = x(i₁). Then we recurse onv using the other indices:Index(v, Array(i₂, i₃, …, iₙ)).
  • But ifx is an array withr > 1 dimensions, we use thefirstr indices to extractv = x(i₁, i₂, i₃, …, iᵣ). Then we recurse onv using theremaining indices:Index(v, Array(iᵣ₊₁, iᵣ₊₂, iᵣ₊₃, …, iₙ)).

This continues until we exhaust alln indices, at which point the valuev is our result.

Lean Indices

The process of"slicing" an array typically involves loops and copying, which are inefficient here. Rather than splitting off two separate arrays at therth index, we simply "reframe" the original array of indices, by adjusting thelower andupper bounds for our "window" of interest.

Consider an inputx which is anr-dimensional array; and an arrayi of indices, ranging from the lower boundl to the upper boundu. Per the algorithm, we want the firstr indices fromi₁ = i(l) throughiᵣ = i(k), wherek = l + r - 1 marks therth index.

So we pass the original indicesi by reference, and simply specify a new window thereon, ranging froml throughk. Seehere for source code.

            ' Extract the value from the array at those indices.            Arr_Index x, v := v, i := i, l := l, u := k            '                         ^       ^       ^            '                         ^       ^^^^^^^^^            '                   indices         window

As for the remaining indices, we do likewise and specify another window fromk + 1 throughu.

            ' Index (recursively) into that value using any further indices.            If k < u Then                Index v, v := v, i := i, l := k + 1, u := u                '                     ^       ^^^^^       ^                '                     ^       ^^^^^^^^^^^^^                '               indices           window            End If

Lean Assignment

Because our data structures may contain both scalar and objective elements, we must replace the static syntax…

' Scalar.v = x(i₁)' Object.Set v = x(i₁)

…with the utilityAssign(), which flexibly assignsany value to a variable. Seehere for source code.

Assign v, x(i₁)

But when we are many levels deep, it would be inefficient for a recursiveFunction likeIndex() toAssign() a return value. Atm levels deep we would requirem - 1 suchAssign() operations, where each returns the recursive result to its caller:

Assign Index, Index(v, i = i, l := …, u := …)

So rather than using aFunction, we implement aSubroutine calledIndexRaw(). This accepts thereference to our variablev, and only when it reaches "bottom" does itAssign() the result tov. Seehere for source code.

    ' Base case: only one index left.    Else        Assign v, x(i(l))    End If

Lean Delegation

Generally speaking, everyFunction of the form*Index() has an*IndexRaw(): a leanSubroutine, which assigns the bottommost result tov. So just asIndex() has anIndexRaw(), ourArr_Index() has anArr_IndexRaw().

Every*Index() takes input and validates it once and for all, before delegating to*IndexRaw(). The latter does the heavy lifting of recursion—but skips validation to avoid redundant steps that burden performance. For the same reason,IndexRaw() actually passes arrays toArr_IndexRaw() rather thanArr_Index().

Questions

I have already detailed most of these asissues on GitHub. Feel free to pose and address additional questions of your own!

  1. Nomenclature: Currently we haveArr_Index() for arrays; along withIndex() andIndex0() for arbitrary structures. But "Index" clashes withINDEX() in Excel, and possibly withWorksheetFunction.Index() in VBA.

    Now this module is inspired bypluck() in R.So should we renameIndex*() asPluck*(), andArr_Index*() asArr_Pluck*()? This should also entail renaming the entireIdx.bas module and indeed theIdx repository.

  2. Diagnostic Messaging: Currently the*Index() functions do not actuallythrow the validation errors they encounter, and I currently useDebug.Print() as a placeholder.

    My instinct is to implement my own "error throwers" likeErrs_ArrayIsUninitialized(), which throw detailed errors with custom codes, rather than (say) a standardError 9.What is best practice for handling validation errors?

  3. Assignment: Thepluck() function also allows assignment:pluck(x, …) <- value.Should I similarly implement "setters" to complement "getters" like*Index()? This is best done as aProperty

    Property Get Arr_Index(arr, indices)   ' ...End PropertyProperty Let Arr_Index(arr, indices, value)   ' ...End PropertyProperty Set Arr_Index(arr, indices, value)   ' ...End Property

    …but the process is daunting forIndex(), which sets a value deeply within an arbitrary structure. Now an object may be modified by reference, and anything that wraps it (as a reference) is updated accordingly. But when the target isnot an object, and it is nestedwithin an array, then we mustfirst modify the target andthen overwrite the array location with ourresult.

    And even objects have their complications! By assumption our objects have a default method forgetting values, so thex(i) syntax always applies forgetting. But the.Item() for aCollection isread-only, so we cannot rely on thex(i) = … syntax. Indeed, theworkaround can be convoluted, and there is no generic implementation for objects in general.

    Finally, thepluck() assignment creates anew "slot" when it does not already exist. While we can easily.Add() to aCollection, once again this is not a generic implementation for objects in general. As for arrays, we can only resize them with aReDim Preserve which might prove prohibitively costly; and multidimensional arrays add yet another layer of complexity.

  4. Multiple Extraction: So far we require each index to be either a numeric (Long) position or a textual (String) key. But if an individual index is instead anarray, then perhaps this should triggeriteration, so that a single call of this form…

    Index(x, Array(5, Array(2, "a", 4), "x"))'                 ^^^^^^^^^^^^^^^^

    …is equivalent to several calls of this form…

    Index(x, Array(5,   2, "x")Index(x, Array(5, "a", "x")Index(x, Array(5,   4, "x")

    …where the results are gathered (into aCollection or array) and returned. This will be quite challenging for multidimensional arrays.Is this feature worth the effort, as a sufficiently logical extension of the existing framework?

  5. pluck() Features: Thepluck() family has further attractive features, like testing withpluck_exists() whether the element actually exists, and havingpluck() safely return a.default (likeNULL) when it does not. As it stands, our*Index() functionsactually bear more resemblance tochuck(), which throws ("chucks") an error rather than defaulting.

    Should we include adefault argument to*Index(), so it better resemblespluck()? TheNull value in VBA corresponds nicely toNULL in R. However, this would obviously complicate anyassignment feature, because theProperty signatures would notmatch properly:

    Property Get Arr_Index(arr, indices, Optional default As Variant = Null)   ' ...End PropertyProperty Let Arr_Index(arr, indices, value)   ' ...End Property
  6. Efficient Assignment: As discussed above underLean Indices andLean Assignment, ourIndexRaw() extracts the element from any multidimensional array, and assigns it tov as a placeholder before recursing further thereon. Seehere for source code.

       ' Extract the value from the array at those indices.   Arr_IndexRaw x, v := v, i := i, l := l, u := k   ' Index (recursively) into that value using any further indices.   If k < u Then       IndexRaw v, v := v, i := i, l := k + 1, u := u   End If

    But while thislooks elegant,would it be more performant to avoid that intermediate step? If so, we must reworkArr_IndexRaw() as aFunction.

       ' Target the element from array at those indices: either extract its value as is...   If Not k < u Then       Assign v, Arr_IndexRaw(x, i := i, l := l, u := k)   ' ...or index (recursively) into it using further indices.   Else       IndexRaw Arr_IndexRaw(x, i := i, l := l, u := k), v := v, i := i, l := k + 1, u := u       '        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   End If
  7. Trivial Indices: Whenu < l and there are no indices, thenArr_IndexRaw() handles this with aCase 0 and aCase Else. Seehere for source code.

       Select Case   Case  0: Assign v, a()   Case  1: Assign v, a(i(l))   Case  2: Assign v, a(i(l),i(l+1))   Case  3: Assign v, a(i(l),i(l+1),i(l+2))   ' ...   Case 60: Assign v, a(i(l),i(l+1),i(l+2),…,i(l+59))   Case Else: Assign v, a()   End Select

    But running out of indices is a rare situation, and it only happens once per extraction. So thisCase 0 doessave us 60 checks in this situation, but it alsoadds one extra check in every situation where indices are present.Would we achieve better performance by removingCase 0, and letting the logic "fall through" toCase Else?

Code

Here is the source code for versionv0.1.0 of myIdx.bas module.

Attribute VB_Name = "Idx"' #############' ## Options ##' #############' Explicitly declare all variables.Option Explicit' ' Hide these developer functions from end users in Excel.' Option Private Module' ##############' ## Metadata ##' ##############Public Const MOD_NAME As String = "Idx"Public Const MOD_VERSION As String = "0.1.0"Public Const MOD_REPO As String = "https://github.com/GregYannes/Idx"' ###############' ## Constants ##' ###############' The most dimensions an array may have.Private Const MAX_ARR_RANK As Long = 60' #########' ## API ##' #########' Manually extract a value (by index) from an arbitrary data structure.Public Function Index0(ByRef x As Variant, _    ParamArray indices() As Variant _) As Variant    Dim i As Variant: i = indices    Assign Index0, Index(x, indices := i)End Function' Programmatically extract a value (by index) from an arbitrary data structure.Public Function Index(ByRef x As Variant, _    ByRef indices As Variant _) As Variant    ' ################    ' ## Validation ##    ' ################        ' Short-circuit for no array.    If Not VBA.IsArray(indices) Then Debug.Print "ERROR: The indices must be an array."        ' Short-circuit for uninitialized...    Dim iRnk As Long: iRnk = Arr_Rank(indices)    If iRnk = 0 Then        Debug.Print "ERROR: The indices must be initialized."            ' ...or multidimensional indices.    ElseIf iRnk > 1 Then        Debug.Print "ERROR: The indices must have exactly one dimension."    End If        ' Short-circuit for no indices.    Dim iLen As Long: iLen = Arr_Length(indices, dimension := 1)    If iLen = 0 Then        Debug.Print "ERROR: At least one index is required."    End If            ' ################    ' ## Extraction ##    ' ################        ' Record the bounds of the indices.    Dim low As Long: low = LBound(indices, 1)    Dim up As Long: up = UBound(indices, 1)        ' Index dynamically into the structure and extract the value there.    IndexRaw x, v := Index, i := indices, l := low, u := upEnd Function' Programmatically extract a value (by index) from a multidimensional array.Public Function Arr_Index(ByRef arr As Variant, _    ByRef indices As Variant _) As Variant    ' ################    ' ## Validation ##    ' ################        ' Short-circuit for no arrays.    If Not VBA.IsArray(arr) Then Debug.Print "ERROR: Input must be an array."    If Not VBA.IsArray(indices) Then Debug.Print "ERROR: The indices must be an array."        ' Short-circuit for uninitialized...    Dim iRnk As Long: iRnk = Arr_Rank(indices)    If iRnk = 0 Then        Debug.Print "ERROR: The indices must be initialized."            ' ...or multidimensional indices.    ElseIf iRnk > 1 Then        Debug.Print "ERROR: The indices must have exactly one dimension."    End If        ' Short-circuit for no indices...    Dim iLen As Long: iLen = Arr_Length(indices, dimension := 1)    If iLen = 0 Then        Debug.Print "ERROR: At least one index is required."            ' ...or for impossibly many.    ElseIf iLen > MAX_ARR_RANK Then        Debug.Print "ERROR: No array may accept more than " & VBA.CStr(MAX_ARR_RANK) & " indices for " & VBA.CStr(MAX_ARR_RANK) & " dimensions."    End If        ' Short-circuit for uninitialized array.    Dim aRnk As Long: aRnk = Arr_Rank(arr)    If aRnk = 0 Then Debug.Print "ERROR: The array must be initialized."        ' Short-circuit for wrong number of indices.    If iLen <> aRnk Then Debug.Print "ERROR: There must be exactly as many indices (" & VBA.CStr(iLen) & ") as dimensions (" & VBA.CStr(aRnk) ") in the array."            ' ################    ' ## Extraction ##    ' ################        ' Record the bounds of the indices.    Dim low As Long: low = LBound(indices, 1)    Dim up As Long: up = UBound(indices, 1)        ' Index dynamically into the array and extract the value there.    Arr_IndexRaw arr, v := Arr_Index, i := indices, l := low, u := upEnd Function' #############' ## Support ##' #############' Lean workhorse for recursive extraction from arbitrary data structures.Private Sub IndexRaw(ByRef x As Variant, _    ByRef v As Variant, _    ByRef i As Variant, _    ByVal l As Long, _    ByVal u As Long _)    ' Recursive case: several indices left.    If l < u Then        ' Index into an array on all its dimensions.        If VBA.IsArray(x) Then            ' Short circuit for uninitialized array.            Dim r As Long: r = Arr_Rank(x)            If r = 0 Then Debug.Print "ERROR: Uninitialized array."                        ' Demarcate the indices for this array.            Dim k As Long: k = l + r - 1                        ' Short-circuit for too few indices.            If k > u Then Debug.Print "ERROR: Too few indices for array."                        ' Extract the value from the array at those indices.            Arr_IndexRaw x, v := v, i := i, l := l, u := k                        ' Index (recursively) into that value using any further indices.            If k < u Then                IndexRaw v, v := v, i := i, l := k + 1, u := u            End If                    ' Index singly into any other structure.        Else            IndexRaw x(i(l)), v := v, i := i, l := l + 1, u := u        End If            ' Base case: only one index left.    Else        Assign v, x(i(l))    End IfEnd Sub' Lean workhorse for extraction from multidimensional arrays.Private Sub Arr_IndexRaw(ByRef a As Variant, _    ByRef v As Variant, _    ByRef i As Variant, _    ByVal l As Long, _    ByVal u As Long _)    Dim n As Long: n = u - l + 1        Select Case n    Case  0: Assign v, a()    Case  1: Assign v, a(i(l))    Case  2: Assign v, a(i(l),i(l+1))    Case  3: Assign v, a(i(l),i(l+1),i(l+2))    Case  4: Assign v, a(i(l),i(l+1),i(l+2),i(l+3))    Case  5: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4))    Case  6: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5))    Case  7: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6))    Case  8: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7))    Case  9: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8))    Case 10: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9))    Case 11: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10))    Case 12: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11))    Case 13: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12))    Case 14: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13))    Case 15: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14))    Case 16: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15))    Case 17: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16))    Case 18: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17))    Case 19: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18))    Case 20: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19))    Case 21: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20))    Case 22: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21))    Case 23: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22))    Case 24: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23))    Case 25: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24))    Case 26: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25))    Case 27: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26))    Case 28: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27))    Case 29: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28))    Case 30: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29))    Case 31: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30))    Case 32: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31))    Case 33: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32))    Case 34: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33))    Case 35: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34))    Case 36: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35))    Case 37: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36))    Case 38: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37))    Case 39: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38))    Case 40: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39))    Case 41: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40))    Case 42: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41))    Case 43: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42))    Case 44: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43))    Case 45: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44))    Case 46: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45))    Case 47: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46))    Case 48: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46),i(l+47))    Case 49: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46),i(l+47),i(l+48))    Case 50: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46),i(l+47),i(l+48),i(l+49))    Case 51: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46),i(l+47),i(l+48),i(l+49),i(l+50))    Case 52: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46),i(l+47),i(l+48),i(l+49),i(l+50),i(l+51))    Case 53: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46),i(l+47),i(l+48),i(l+49),i(l+50),i(l+51),i(l+52))    Case 54: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46),i(l+47),i(l+48),i(l+49),i(l+50),i(l+51),i(l+52),i(l+53))    Case 55: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46),i(l+47),i(l+48),i(l+49),i(l+50),i(l+51),i(l+52),i(l+53),i(l+54))    Case 56: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46),i(l+47),i(l+48),i(l+49),i(l+50),i(l+51),i(l+52),i(l+53),i(l+54),i(l+55))    Case 57: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46),i(l+47),i(l+48),i(l+49),i(l+50),i(l+51),i(l+52),i(l+53),i(l+54),i(l+55),i(l+56))    Case 58: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46),i(l+47),i(l+48),i(l+49),i(l+50),i(l+51),i(l+52),i(l+53),i(l+54),i(l+55),i(l+56),i(l+57))    Case 59: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46),i(l+47),i(l+48),i(l+49),i(l+50),i(l+51),i(l+52),i(l+53),i(l+54),i(l+55),i(l+56),i(l+57),i(l+58))    Case 60: Assign v, a(i(l),i(l+1),i(l+2),i(l+3),i(l+4),i(l+5),i(l+6),i(l+7),i(l+8),i(l+9),i(l+10),i(l+11),i(l+12),i(l+13),i(l+14),i(l+15),i(l+16),i(l+17),i(l+18),i(l+19),i(l+20),i(l+21),i(l+22),i(l+23),i(l+24),i(l+25),i(l+26),i(l+27),i(l+28),i(l+29),i(l+30),i(l+31),i(l+32),i(l+33),i(l+34),i(l+35),i(l+36),i(l+37),i(l+38),i(l+39),i(l+40),i(l+41),i(l+42),i(l+43),i(l+44),i(l+45),i(l+46),i(l+47),i(l+48),i(l+49),i(l+50),i(l+51),i(l+52),i(l+53),i(l+54),i(l+55),i(l+56),i(l+57),i(l+58),i(l+59))    Case Else: Assign v, a()    End SelectEnd Sub' ###############' ## Utilities ##' ###############' Assign a value (scalar or objective) to a variable.Public Sub Assign( _    ByRef var As Variant, _    ByVal val As Variant _)    If VBA.IsObject(val) Then        Set var = val    Else        var = val    End IfEnd Sub' Get the length (along a dimension) of an array.Public Function Arr_Length(ByRef arr As Variant, _    Optional ByVal dimension As Long = 1 _) As Long    On Error GoTo BOUND_ERROR    Arr_Length = UBound(arr, dimension) - LBound(arr, dimension) + 1    Exit Function    BOUND_ERROR:    Arr_Length = 0End Function' Get the "rank" of an array: the count of its dimensions.Public Function Arr_Rank(ByRef arr As Variant) As Long    Dim tst As Long    Arr_Rank = 0        On Error GoTo BOUND_ERROR    Do While True        Arr_Rank = Arr_Rank + 1        tst = UBound(arr, Arr_Rank)    Loop    BOUND_ERROR:    Arr_Rank = Arr_Rank - 1End Function
askedOct 22 at 21:14
Greg's user avatar
\$\endgroup\$
5
  • \$\begingroup\$Pleaseedit your question so that the title describes thepurpose of the code, rather than itsmechanism. We really need to understand the motivational context to give good reviews. It's best to describewhat value this code provides to its user.\$\endgroup\$CommentedOct 23 at 10:17
  • \$\begingroup\$@TobySpeight Well, "indexing into nested data structures"is the purpose of my code, while my recursive algorithm is the mechanism. The documentation forpluck() phrases its purpose similarly:"index deeply and flexibly into data structures". I haveedited my overview to reflect this.\$\endgroup\$CommentedOct 23 at 17:22
  • 1
    \$\begingroup\$I see - thank you for the clarification.:-)\$\endgroup\$CommentedOct 24 at 6:55
  • \$\begingroup\$The questions are useful, and I get that you want feedback on the overall API/architecture, but you need to post the actual source code as part of your question in case the link dies (that would render reviews useless for future readers), and if you want reviewers to "pose and address additional questions" then people need to see the source code :)\$\endgroup\$CommentedOct 27 at 12:35
  • \$\begingroup\$@Greedo Thanks for the advice! I haveedited my post to include the source code. I'm not quite sure what you mean by the link "dying", because it is tagged to a specific (pre)release on GitHub, but this update should forestall any issues on SO. 😊\$\endgroup\$CommentedOct 28 at 15:54

0

You mustlog in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.