【问题标题】:Excel VBA Insert New Row into an ArrayExcel VBA 将新行插入数组
【发布时间】:2021-08-13 19:52:08
【问题描述】:

我有一个二维数组,我想在数组中间的某个行号处插入一些行。

数组已经有现有信息,所以如果我想简单地将新信息放在中间,那么 ReDim Preserve 就不能很好地工作。

有什么想法吗?

【问题讨论】:

  • 创建一个所需大小的新数组,循环第一个数组并将值放在您想要的位置。
  • 复制到ArrayListDictionary。将新项目添加到您想要的位置。然后重新创建一个数组。

标签: arrays excel vba insert row


【解决方案1】:

假设有两个 1-based 2-dim 数据字段输入,我演示了 @FaneDuru 的有效方法的替代方法,使用单独的 combo list 创建作为 数据容器 并允许通过现在可分配的.AddItem 方法进行简单的项目插入。

请注意,这种方法当然可以在许多方面进行改进,例如通过允许输入数组使用不同的索引基数。 - 有条不紊的提示: 分配从零开始的组合的.Column 属性(即倒置的.List 属性)并将其转回允许此处重新获得输入数组的原始从一开始的索引作为ReDim Preserve 会失败(它只能重新调整最后一个维度)

Sub AddElement(datafield, ByVal rowNum As Long, newData)
'Note: assumes 1-based 2dim input arrays with same column counts
'create zero-based combo container on the fly
With CreateObject("Forms.ComboBox.1")
    .list = datafield     ' assign datafield to zero-based list elems
    .AddItem , rowNum - 1 ' add Null values to zero-based list index
    'assign new data to each zero-based list column
        Dim col As Long
        For col = LBound(newData, 2) To UBound(newData, 2)
            .list(rowNum - 1, col - 1) = newData(1, col)
        Next col
    'overwrite original datafield with transposed list values to regain 1-based elems
    datafield = Application.Transpose(.Column)    ' overwriting data (with zerobased dimensions)
End With

End Sub

由于 datafield 参数通过引用 (ByRef) 隐式传递,原始数据输入将被覆盖。

插入新的第二行的示例调用

Dim data:    data = Sheet1.Range("A1:C4").Value
Dim newData: newData = Sheet2.Range("A1:C1").Value
AddElement data, 2, newData

【讨论】:

  • 如果有启发性或有帮助,请随意学习 Fane Duru 的棘手答案@B-M
  • 非常有趣!投票赞成。我不知道这是否可以在没有数组大小限制的情况下使用,但这是个好主意。我认为它可以改进为不需要任何Application.Transpose,众所周知它有大小限制。我有一个想法,我(认为)知道不能使用 list 属性而不是转置 .column。现在没有时间处理它,但如果我的想法会被现实覆盖并且我可以在 5 - 10 分钟内完成,我将发布一个新的答案来展示它。无论如何,不​​错的方法...
【解决方案2】:

重播@T.M.不错的方法:

尝试使用不需要转置列数组的下一个函数:

Function AddElement(datafield, ByVal rowNum As Long, newData) As Variant
    'Note: assumes 1-based 2dim input arrays with same column counts
    'create zero-based combo container on the fly
    With CreateObject("Forms.ComboBox.1")
        .list = datafield     ' assign datafield to zero-based list elems
        .AddItem , rowNum - 1 ' add Null values to zero-based list index
        'assign new data to each zero-based list column
            Dim col As Long
            For col = LBound(newData, 2) To UBound(newData, 2)
                .list(rowNum - 1, col - 1) = newData(1, col)
            Next col
        AddElement = .list 'it returns a zero based 2D array...
    End With
End Function

可以这样测试:

Sub testAddArrayrow()
 Dim sh As Worksheet, newArr: sh = ActiveSheet  'was easier for me to check...
 Dim data:    data = sh.Range("A1:C4").Value
 Dim newData: newData = sh.Range("A6:C6").Value
    newArr = AddElement(data, 2, newData)
    sh.Range("P1").Resize(UBound(newArr) + 1, UBound(newArr, 2) + 1).Value = newArr '+ 1 because of zero bazed 2D returned array
End Sub

我们必须进行一些研究以检查数组大小限制(如果有)。没有这样的限制会很有趣,但我不能对这个方向抱太大希望...... :)

无论如何,这个绝妙的想法仍然存在......

【讨论】:

  • 如果打算将(现在基于 的)数据重写到工作表范围,而不需要坚持原来的基于 1 的数据字段,则返回 .List结果显然是首选方式(顺便说一句,我原来的方法)。无论如何,有趣的是,写回数据并不关心边界@FaneDuru :)
  • @T.M.我想我理解了你使用 .column 属性的原因,我只是尝试展示如何将这样一个返回的数组放在一个范围内。
【解决方案3】:

请尝试下一个方法:

Sub TestInsertRow()
    Dim sh, arr, arrInsR, arrFin
    
    Set sh = ActiveSheet
    arr = sh.[A1:C5].Value       'array to insert a row
    arrInsR = sh.[A11:C11].Value 'row to be inserted
    arrFin = InsertRowElab(arr, arrInsR, 3) 'inserted row to be the third
   sh.[J10].Resize(UBound(arrFin), UBound(arrFin, 2)).Value = arrFin
End Sub

Private Function InsertRowElab(arr As Variant, arrIns As Variant, insRowNo As Long) As Variant 'it inserts a row
   Dim i&, k&, Ar, arrR, arrRows, arrCols
   
   arrR = Application.Transpose(Application.Evaluate("row(1:" & UBound(arr) & ")")) 'build the rows array
    Debug.Print "Joined rows array: " & Join(arrR, "#"):                                        'so the joined array looks
   arrRows = Split(Replace(Join(arrR, "|"), insRowNo - 1 & "|", insRowNo - 1 & "|0|"), "|")      'insert the row, placing 0 in the array
    Debug.Print "Joined rows array containing the inserted row (0): " & Join(arrRows, "#")       'so the joined array containing the new row (0) looks
   arrCols = Application.Transpose(Application.Evaluate("row(1:" & UBound(arr, 2) & ")")) 'Array(1, 2, 3)
   Ar = Application.Index(arr, Application.Transpose(arrRows), arrCols)
   'fill the inserted row:
   For i = LBound(Ar) To UBound(Ar, 2): Ar(insRowNo, i) = arrIns(1, i): Next i
   InsertRowElab = Ar
End Function

【讨论】:

  • 仅供参考,由于转置的限制,这不适用于大型数组。
  • @Scott Craner 我知道它的局限性。在大型数组的情况下,Transpose 函数限制可以使用自定义转置函数来解决,速度相当快。容易写。我只尝试展示一种在二维数组中插入一行(它可以适应插入更多行的切片)的方法,正如问题中所要求的那样。只是为了展示如何完成......
  • 通过连续 joinreplacesplit action +:) - 看看Some peculiarities of the the Application.Index function@FaneDuru,其他用户可能更容易理解这种方法
  • @T.M.我在这里有一个朋友,我和他讨论过他的问题...:)
  • 感谢您始终有价值的解决方案和贡献。 - 仅供参考,就像您一样,也喜欢 alternatives,您可能会对我展示组合列表车辆的帖子感兴趣。 @FaneDuru
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多