vba - 如何在 Excel 中将范围转换为单调列表

标签 vba excel excel-formula

我有一系列单元格,在 Excel 中看起来像这样

Start   End     Cat 1   Cat 2   Value
2011    2015    1       1       2.09
2011    2015    1       2       1.71
2011    2015    2       1       0.66
2011    2015    2       2       2.07
2011    2015    3       1       0.66
2011    2015    3       2       2.07
2016    2020    1       1       3.72
2016    2020    1       2       2.22
2016    2020    2       1       1.38
2016    2020    2       2       2.34
2016    2020    3       1       1.38
2016    2020    3       2       2.34
...

例如,第一行表示对于 2011-2015 年,值 2.09 对 [category1 = 1][category2 = 1] 有效(忽略类别对问题的意义)。

我想要的是扩展列表,使其看起来像这样

Year    Cat 1   Cat 2   Value
2011    1       1       2.09
2011    1       2       1.71
2011    2       1       0.66
2011    2       2       2.07
2011    3       1       0.66
2011    3       2       2.07
2012    1       1       2.09
2012    1       2       1.71
2012    2       1       0.66
2012    2       2       2.07
2012    3       1       0.66
2012    3       2       2.07
...

即它为第一个范围 (2011-2015) 中的每个值复制类别 1、类别 2 和值列,然后为第二个年份范围 (2016-2020) 复制第二组列,依此类推。

最好的方法是什么?是否有一些我可以应用的 Excel 公式技巧或者是编写一些宏的最佳方法?

最佳答案

这是一种不同的方法,它速度快如闪电并提供所需的输出:

Sub MakeNewTable()

Dim k As Long, i As Long, j As Long, r As Long
Dim sh1 As Worksheet, sh2 As Worksheet
Dim maxYear As Long, minYear As Long, nrow As Long
Dim groups() As Double, myData As Variant

    Set sh1 = Sheets("Sheet1")
    Set sh2 = Sheets("Sheet2")
    myData = sh1.UsedRange '' Put your range here
    nrow = UBound(myData, 1)

    minYear = Application.WorksheetFunction.Min(Range(sh1.Cells(2, 1), sh1.Cells(nrow + 1, 1)))
    maxYear = Application.WorksheetFunction.Max(sh1.Range(sh1.Cells(2, 2), sh1.Cells(nrow + 1, 2)))

    ReDim groups(minYear To maxYear, 1 To 3, nrow)

    For i = nrow To 2 Step -1
        For j = myData(i, 1) To myData(i, 2)
            For k = 1 To 3: groups(j, k, i) = myData(i, k + 2): Next k
            groups(j, 1, 1) = i  '' Getting first time a value appears... Used in loop below
            If i > groups(j, 2, 1) Then groups(j, 2, 1) = i  '' Getting last time a value appears
        Next j
    Next i

    k = 2

    For i = minYear To maxYear
        For j = groups(i, 1, 1) To groups(i, 2, 1)
            If groups(i, 1, j) > 0 Then
                sh2.Cells(k, 1) = i
                For r = 1 To 3: sh2.Cells(k, r + 1) = groups(i, r, j): Next r
                k = k + 1
            End If
        Next j
    Next i

End Sub

它利用在数组中存储和操作数据的优势,因此所有繁重的工作都在本地完成。我通过创建一个名为 groups 的分组数组来组织数据,该数组利用索引来快速组织数据。应该注意的是,该算法也非常通用,这意味着,数据是否已经按年份很好地划分并不重要。例如,此算法适用于以下表格:

Start    End
 2011   2015 ...
 2008   2013 ...
 2018   2021 ...
 2011   2015 ...
 1991   2003 ...
 1998   2000 ...
    etc. 

关于vba - 如何在 Excel 中将范围转换为单调列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40095546/

相关文章:

vba - 更改范围的条件格式

vba - 为什么我的 RecordCount 不应该是 0?

vba - 从电子表格引用单元格并填充相应的单元格

excel - 使用 =IF 公式在表之间拉取数据

excel - 解释LOOKUP公式

excel - 如何使用 VBA 获取前五篇新闻文章的名称和链接

ms-access - 过滤器和 where 子句之间的区别

c# - 操作失败,对具有 IID 的接口(interface)的 COM 组件上的 QueryInterface 调用失败,因为库未注册

vba - 偏移到另一列并在满足条件时停止

excel - 比较 A 列和 B 列并创建包含仅存在于 A 列中的值的新列