【问题标题】:Repeat a Number N Times in an Array在一个数组中重复一个数字 N 次
【发布时间】:2016-08-02 10:41:05
【问题描述】:

使用 Excel VBA。

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

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

是否有一个巧妙的解决方案(不经过循环)来做到这一点?在几乎任何其他统计语言中,这是通过重复函数完成的。例如 R 中的“rep”函数或 Matlab 中的“repmat”函数:

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

首先不对所有内容进行硬编码的原因是因为实际数组的长度取决于其他一些变量。

【问题讨论】:

  • 不能用Application.WorksheetFunction.Rept()吗?

标签: arrays vba excel repeat


【解决方案1】:

输出: 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

输出: 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

【讨论】:

  • 您的第一个解决方案非常优雅。我喜欢它可以灵活地重新排列数组的方式。
  • 非常感谢。这将完成这项工作,并且确实很灵活。显然没有内置函数可以解决这个问题。我认为你和@JohnColeman 基本上为我创建了这个函数。那么循环是不可避免的。
  • 感谢您的勾选!这是一个有趣的问题。将 John Coleman 的答案与我自己的答案结合起来会很有趣。
【解决方案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 不能有可选参数,这很糟糕。
  • @ThomasInzina 是的,我发现自己希望我可以同时使用参数数组和可选参数(尽管可能有 some 方式——我不是 100% 确定我没有遗漏什么)。我倾向于做更多的 Python 编程而不是 VBA 编程,而且每当我回到 VBA 时,我经常会发现自己失去了 Python 的一些功能和灵活性。在 Python 中,这样的事情很容易。可以修改我的函数,以便最后一个可选参数可以是 TrueFalse 而不是(或除此之外)一个 int —— True 可能被解释为“Base1”。
【解决方案3】:

像这样?

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 已经知道如何在循环中初始化数组,但想知道是否有办法避免这种显式循环。
  • @JohnColeman:根据您的定义,仅仅因为“这不是很灵活”并不意味着应该被否决。更不用说由 OP 决定了
  • 缺乏灵活性是相当极端的(因此投反对票)。它不容易推广到像Array(4,4,7,7,7,7) 这样简单的东西,更不用说例如Array("A","A","A","B","B")。事实上,样本数组中的值由两个连续的整数组成。
猜你喜欢
  • 2019-07-22
  • 2016-04-19
  • 1970-01-01
  • 2021-11-30
  • 2011-11-13
  • 1970-01-01
  • 2020-08-17
  • 2021-12-07
  • 2017-11-10
相关资源
最近更新 更多