我想将四列中的数据转换为矩阵表。我试图使用OFFSET函数,但它可以正常工作,但是我的数据太大(大约100,000个单元格),并且崩溃了。

所以,我很想尝试通过宏来做到这一点,你能建议怎么做吗?或者,您有任何更好的建议都很好。

PS。我从此站点here使用了OFFSET公式。

最佳答案

好玩的问题!因为您遇到了涉及数据大小的问题,所以我尝试避免使用诸如字典之类的对象(我不知道字典可以容纳多少)。取而代之的是,我创建了一个程序,该程序可以跟踪很少的数据,但是最终会不断地从文件中读取/写入文件:这会非常慢,但是对于非常大的文件却可以使用。

无论如何,请尝试将以下代码复制并粘贴到VBA模块中,然后在文件上运行它。您可能需要更改某些行和列的值。

编辑:我使它适用于您给的示例图片,但这是一团糟。明天我会更清楚(g2g)
编辑:它已更新!仔细评论等,您可以根据自己的喜好进行修改。

摘要


在数据表下方建立矩阵表
遍历数据表中的行并将其添加到矩阵表中
如果矩阵表尚未包含数据的行或列,请进行创建,否则将其放置在现有表中


例:


代码:(所以摆脱了空白:(我认为我的帖子太长了)

'Start and end row of the original data
Private dataStartRow As Long
Private dataEndRow As Long

'The start row/column of the matrix
Private matrixStartRow As Long
Private matrixStartCol As Long

'How many rows/columns in the matrix
Private matrixRowLength As Long
Private matrixColLength As Integer

Public Sub makeMatrixTable()
    'Sets initial values for variables
    initializeValues
    'Builds table
    buildTable
End Sub

Private Function initializeValues()
    'The actual data probably begins on row 2, because row 1 is usually used for column titles
    dataStartRow = 2
    'Get last row of data
    dataEndRow = ActiveSheet.UsedRange.Rows.Count

    'By adding 2, we create a gap row between our new matrix table and the original data table
    matrixStartRow = dataEndRow + 2
    'The matrix values begin after column 2, because columns 1&2 are used for titles
    matrixStartCol = 2

    matrixRowLength = 0
    matrixColLength = 0
End Function

Private Function buildTable()
    Dim dataRow As Long
    Dim matrixRow As Long
    Dim matrixCol As Integer
    Dim value As String

    'The keys are the column/row titles
    'I'm using the work "key" because we're mimicking a dictionary object by only using a key once
    'in this case it's a little more complicated, as we have 3 keys (2 row keys, 1 column key)
    Dim rowKey1 As String, rowKey2 As String
    Dim colKey As String

    'loop through all rows containing data
    For dataRow = dataStartRow To dataEndRow
        'get keys from data
        rowKey1 = CStr(ActiveSheet.Cells(dataRow, 1).value)
        rowKey2 = CStr(ActiveSheet.Cells(dataRow, 3).value)
        colKey = CStr(ActiveSheet.Cells(dataRow, 2).value)

        'find if we have already created rows for the row keys, and if so return the row (else -1)
        matrixRow = rowExistsInMatrix(rowKey1, rowKey2)
        'find if we have already created a column for the column key, and if so return the row (else -1
        matrixCol = colExistsInMatrix(colKey)

        'Our matrix does not have a row with those row keys, so we must create one
        If matrixRow = -1 Then
            'increase the size of our matrix
            matrixRowLength = matrixRowLength + 1
            'get row that is not in use
            matrixRow = matrixStartRow + matrixRowLength
            'add the new keys to matrix
            ActiveSheet.Cells(matrixRow, 1).value = rowKey1
            ActiveSheet.Cells(matrixRow, 2).value = rowKey2
        End If

        'We don't have a column that matches the column key
        If matrixCol = -1 Then
            'increase size of matrix table
            matrixColLength = matrixColLength + 1
            'get column that is not in use
            matrixCol = matrixStartCol + matrixColLength
            'add new key to matrix
            ActiveSheet.Cells(matrixStartRow, matrixCol).value = colKey
        End If

        'get the value to be placed in the matrix from column 4
        value = CStr(ActiveSheet.Cells(dataRow, 4).value)
        'place value
        ActiveSheet.Cells(matrixRow, matrixCol).value = value

    Next dataRow
End Function

'Checks to see if the key from the data table exists in our matrix table
'if it does, return the row in the matrix table
'else return -1
Private Function rowExistsInMatrix(dataKey1 As String, dataKey2 As String) As Long
    Dim matrixRow As Long
    Dim matrixKey1 As String, matrixKey2 As String

    'loop through rows of matrix
    For matrixRow = matrixStartRow To matrixStartRow + matrixRowLength
        'get keys from matrix
        matrixKey1 = CStr(ActiveSheet.Cells(matrixRow, 1).value)
        matrixKey2 = CStr(ActiveSheet.Cells(matrixRow, 2).value)

        'do the keys match
        If dataKey1 = matrixKey1 And dataKey2 = matrixKey2 Then
            rowExistsInMatrix = matrixRow
            Exit Function
        End If
    Next matrixRow

    rowExistsInMatrix = -1
End Function

'Same as rowExistsInMatrix but loops through column titles
Private Function colExistsInMatrix(dataKey As String) As Long
    Dim matrixKey As String
    Dim matrixCol As Integer

    'loop through columns
    For matrixCol = matrixStartCol To matrixStartCol + matrixColLength
        matrixKey = CStr(ActiveSheet.Cells(matrixStartRow, matrixCol).value)

        'does a key match
        If matrixKey = dataKey Then
            colExistsInMatrix = matrixCol
            Exit Function
        End If
    Next matrixCol

    colExistsInMatrix = -1
End Function

09-05 12:28