在一个数组中重复一个数字N次

4

与Excel VBA一起工作。

我正在尝试创建一个带有重复模式的数组,就像这样:

a = Array(1,1,1,1,1,2,2,2,2,2,2)

有没有一个简洁的解决方案(不需要循环)来完成这个任务?在几乎任何其他统计语言中,这都可以使用repeat函数来完成。例如,在R中使用“rep”函数或在Matlab中使用“repmat”函数:

a = [repmat(1,1,5),repmat(2,1,6)]

不要一开始就将所有内容硬编码的原因是因为实际数组的长度取决于其他变量的不同值。


你能不能不使用 Application.WorksheetFunction.Rept() - Brian
3个回答

4

输出: A,B,B,1,1,1,2,2,2,2

Sub ArrayHack()
    Dim a()

    BuildArray a, "A", 1
    BuildArray a, "B", 2
    BuildArray a, 1, 3
    BuildArray a, 2, 4

    Debug.Print Join(a, ",")

End Sub

Function BuildArray(a As Variant, v As Variant, n As Integer)
    Dim i As Integer, count As Integer

    On Error Resume Next
        count = UBound(a)
        If Err.Number <> 0 Then
            ReDim a(0)
            count = -1
        End If
    On Error GoTo 0

    ReDim Preserve a(count + n)

    For i = 1 To n
        a(count + i) = v
    Next

End Function

Output: 1,1,1,1,1,2,2,2,2,2

Sub ArrayHack2()
    Dim a
    Dim s As String
    s = Replace(String(5, ","), ",", 1 & ",") & Replace(String(5, ","), ",", 2 & ",")
    s = Left(s, Len(s) - 1)

    a = Split(s, ",")

    Debug.Print Join(a, ",")

End Sub

你的第一个解决方案非常优雅。我喜欢它可以灵活地重新定义数组的方式。 - John Coleman
非常感谢。这将完成任务并确实很灵活。显然没有内置函数可以解决这个问题。我认为你和@JohnColeman基本上为我创建了这个函数。那么循环是不可避免的。 - Jingwei Yu
谢谢您的勾选!这是一个有趣的问题。将John Coleman的答案与我的答案结合起来会很有趣。 - user6432984

2

以下是一个比较灵活的函数:

Function BuildArray(ParamArray params()) As Variant
    Dim A As Variant, v As Variant
    Dim i As Long, j As Long, k As Long, n As Long, m As Long, b As Long

    n = UBound(params)

    If n Mod 2 = 0 Then
        b = params(n)
        n = n - 1
    End If

    For i = 1 To n Step 2
        m = m + params(i)
    Next i

    ReDim A(b To b + m - 1)
    k = b

    For i = 0 To n - 1 Step 2
        v = params(i)
        For j = 1 To params(i + 1)
            A(k) = v
            k = k + 1
        Next j
    Next i

    BuildArray = A
End Function

它可以接受任意数量的参数。如果有偶数个参数,则将它们分成连续的一对,形式为v,i,其中v是值,i是重复该值的次数,返回第一个索引为0的结果数组。如果传递的参数数量为奇数,则最后一个参数被解释为数组的基础。例如:
Sub test()
    Dim A As Variant

    A = BuildArray(1, 3, 2, 4) 'creates 0-based array [1,1,1,2,2,2,2]
    'verify:
    Debug.Print "A = " & LBound(A) & " to " & UBound(A)
    Debug.Print "Items: " & Join(A, ",")

    A = BuildArray(1, 3, 2, 4, 1) 'creates 1-based array [1,1,1,2,2,2,2]
    'verify:
    Debug.Print "A = " & LBound(A) & " to " & UBound(A)
    Debug.Print "Items: " & Join(A, ",")
End Sub

输出:

A = 0 to 6
Items: 1,1,1,2,2,2,2
A = 1 to 7
Items: 1,1,1,2,2,2,2

我希望我能想到使用ParamArray。我更喜欢isBase1而不是非成对值。很遗憾,您无法在ParamArray中使用可选参数。 - user6432984
@ThomasInzina 是的,我发现自己希望能够同时使用ParamArray和可选参数(虽然也许有某种方法——我不确定是否漏掉了什么)。我倾向于做更多的Python编程而不是VBA编程,每当我回到VBA时,我经常发现自己想念Python的一些强大和灵活性。在Python中,这样的事情很容易实现。我的函数可以被修改,使得最后一个可选参数可以是TrueFalse而不是(或者除了)一个整数——其中True可能被解释为“Base1”。 - John Coleman

0

像这样吗?

Const U = 11                                        'U = (4 + Max(i)) * Max(i) + Max(j)
Sub ManipulatingArray()
Dim InputArray As String, i As Long, j As Long, MyArray(1 To U) As Variant
For i = 0 To 1
    For j = 1 To 5 + i
        MyArray((4 + i) * i + j) = i + 1
    Next
Next
Debug.Print Join(MyArray, ",")
End Sub

上述代码将会输出与您的示例相同的结果。


这不是很灵活的。OP已经知道如何在循环中初始化数组,但想知道是否有一种避免这种显式循环的方法。 - John Coleman
@JohnColeman:仅仅因为根据你的定义,“这不是很灵活”,并不意味着它应该被踩。更不用说是由OP决定了。 - Anastasiya-Romanova 秀
缺乏灵活性相当极端(因此被踩了)。它不容易推广到像Array(4,4,7,7,7,7)这样简单的东西,更不用说例如Array("A","A","A","B","B")。它将示例数组中的值硬编码为两个连续整数的事实。 - John Coleman

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