【问题标题】:Combine 2 Ranges into an Array and filter将 2 个范围组合成一个数组并过滤
【发布时间】:2020-01-10 11:40:44
【问题描述】:

我有 2 个范围,都具有相同的行数,不同的列数(可能会有所不同)。

范围 1:

A,   1,   1,   1
B,   2,   4,   8
C,   3,   9,  27
D,   4,  16,  64

范围 2:

1,       1
16,     64   
81,    
256,   1024

我想将这些值导入 Excel 中的多数组,但前提是范围 2 的第 n(本例中为第 2 列)列不是空值。那么我最终会得到一个如下所示的数组:

输出 1:

A,   1,   1,   1,    1,     1
B,   2,   4,   8,   16,    32   
D,   4,  16,  64,  256,  1024

到目前为止——我已经启动了一个函数:

Function Report(rng1 As Range, rng2 As Range)
Dim matrix() As Double
Dim all_rng As Range
    all_rng = Union(rng1, rng2)

End Function

【问题讨论】:

  • 你想要一个二维数组还是一个包含其他一维数组的一维数组?
  • 一个二维数组,第二个范围的值刚刚附加到结束列

标签: arrays excel vba filter


【解决方案1】:

这是可能的决定。
备注:
1.为了测试方便,我把Function改成了Sub,因为我不能一步步走函数
2. 有几行用于测试目的(用 cmets 标记)
3. 我假设要填写的正确列数rng2 在它的第一行
4.有.Select语句的注释行 - 取消注释,按F8一步一步,你会看到它是如何工作的。

答案。

我把你的矩阵是这样的:

并且从第 10 行开始有这样的输出:

代码如下:

Sub Report() 'rng1 As Range, rng2 As Range)
Dim matrix() As Variant ' use variant if you have a mix of letters and numbers
Dim x As Long, y As Long
Dim r As Long, c As Long
Dim rows() As Long, i As Long, rowCnt As Long


' used for test purposes
Dim rng1 As Range, rng2 As Range
Set rng1 = Range(Cells(1, 1), Cells(4, 4))
Set rng2 = Range(Cells(1, 9), Cells(4, 10))


' find out columns count per each range's row 1
x = Range(rng1.Cells(1, 1), rng1.Cells(1, rng1.Columns.Count)).Columns.Count

' I assume that the correct number of columns in rng2 is in the first row
' you may change the row number if needed
y = Range(rng2.Cells(1, 1), rng2.Cells(1, rng2.Columns.Count)).Columns.Count

' check that all rows have all columns filled
For i = 0 To rng1.rows.Count - 1
    ' if all columns in rng2 are filled then add number of the row to an array of row numbers
    If Not rng2.Cells(i + 1, y) = "    " Then ' fix evaluation condition if needed - that is what was copied from post
        ReDim Preserve rows(rowCnt)
        rows(rowCnt) = i + 1
        rowCnt = rowCnt + 1
    End If
Next

i = UBound(rows) - 1

' set dimension of an matrix array
ReDim matrix(rows(i), x + y)

' start filling the matrix

' go through matrix by row
For r = LBound(rows) To UBound(rows)
        ' fill each row column by column

        'gothrough first range - it has x columns in it
        For c = 0 To x - 1
'        rng1.Cells(rows(r), c + 1).Select
            matrix(r, c) = rng1.Cells(rows(r), c + 1).Value
        Next

        ' then without changing matrix's row
        ' go through second range - it has y columns
        For c = 0 To y - 1
'        rng2.Cells(rows(r), c + 1).Select
            matrix(r, c + rows(UBound(rows))) = rng2.Cells(rows(r), c + 1).Value
        Next
Next

' print the matrix to the sheet (optional - delete when convert this back to Function)
For r = LBound(matrix) To UBound(matrix)
    For c = 0 To x + y - 1
        Cells(10 + r, c + 1) = matrix(r, c)
    Next
Next
End Sub

如果您有任何问题,请向 cmets 提出。

【讨论】:

  • 你可以简单地使用x = rng1.columns.count和y = rng2.columns.count,不需要假设。
  • 道歉 - 我确实有一个问题 - 当我将其转换为函数时,ReDim Preserve rows(rowCnt) 出现错误
  • 什么样的错误? (回家后会回答)
  • 抱歉 - 我修复了这个错误 - 这是由于我的 Dim 中的错误。我没有声明它。
  • 现在一切正常 - 您的代码令人难以置信,谢谢。你是我今天能遇到的世界上最好的人:D
【解决方案2】:

数组替代

只是为了演示一种使用数组而不是循环遍历每个单元格的结构清晰的方法:

  1. 将数据分配给数组onetwo
  2. 将第二个数组的列值添加到重新调整维度的数组一
  3. 通过删除空行重构结果数组(检查数组two 中的第n 列) - 通过单个代码行(使用辅助函数)
  4. 将结果写入任何目标范围 - 通过单个代码行
Sub Report(rng1 As Range, rng2 As Range)
  ' [1a] assign data to arrays one and two
    Dim one(), two()                            ' declare variant arrays
    one = rng1.Value:  two = rng2.Value         ' results in 2-dimensioned 1-based arrays
  ' [1b] count columns in both arrays
    Dim cols1 As Long: cols1 = UBound(one, 2)
    Dim cols2 As Long: cols2 = UBound(two, 2)

  ' [2a] redimension array one (by adding the column count of array two)
    ReDim Preserve one(1 To UBound(one), 1 To cols1 + cols2)
  ' [2b] add two-values to array one
    Dim r As Long, col2 As Long                 ' declare row counter and column counter of array two
    For r = 1 To UBound(one)                    ' loop through rows (assuming same rows count in both arrays)
        For col2 = 1 To cols2                   ' loop through columns of array two
            one(r, cols1 + col2) = two(r, col2) ' ...  add all column values of array two to array one
        Next col2
    Next r

  ' [3a] get nth column of array two (for late check of empty row)
    Dim arr()
    arr = Application.Transpose(Application.Index(two, 0, cols2))  ' get "flat" 1-dim and 1-based array
  ' [3b] RESTRUCTURE via Application.Index() function (deleting empty row in nth column of array two)
    one = Application.Index(one, getRowno(arr), Application.Transpose(Evaluate("row(1:" & UBound(one, 2) & ")")))

  ' [4] write to any target range (~> e.g. CodeName Sheet2)
    Sheet2.Range("L10").Resize(UBound(one, 1), UBound(one, 2)) = one

End Sub

辅助函数getRowNo()

Function getRowNo(arr) As Variant()
' Note: receives last column values of array two as 1-dim 1based array
' Purp: returns 2-dim 1-based array with non-empty row numbers of array two
    Dim i As Long, ii As Long, tmp()
    ReDim tmp(1 To 1, 1 To UBound(arr))     ' provide for temporary array
    For i = LBound(arr) To UBound(arr)
        If Len(arr(i) & "") Then            ' omit empty item
            ii = ii + 1                     ' increment temp counter
            tmp(1, ii) = i                  ' enter row number of original column data
        End If
    Next i
    ReDim Preserve tmp(1 To 1, 1 To ii)     ' correct last dimension
    getRowno = Application.Transpose(tmp)   ' return 2-dim array with rownumbers to be preserved
End Function

【讨论】:

    猜你喜欢
    • 2021-01-15
    • 2015-05-26
    • 2020-05-17
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    • 2020-06-22
    • 2019-05-29
    • 1970-01-01
    相关资源
    最近更新 更多