我从其他地方找到了这段代码,并对其进行了一些修改以满足我的需求,但我不完全确定它是如何工作的。我想知道它是如何工作的,因为我想进一步修改它,但我对 VBA 比较陌生,不明白 Resize、Index 和 Evaluate 函数如何在这个宏中协同工作。
Sub RearrangeColumns()
Dim newColumnOrder As Variant
newColumnOrder = Array(1, 2, 3, 4, 41, 42, 43, 44, 5, 6, 49, _
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, _
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, _
35, 36, 37, 38, 39, 40, 45, 46, 47, 48, 50, 51, 52)
Range("A1").Resize(Cells.Find("*", , xlFormulas, , xlRows, xlPrevious).Row, UBound(newColumnOrder) + 1) = _
Application.Index(Cells, Evaluate("ROW(1:" & Cells.Find("*", , xlFormulas, _
, xlRows, xlPrevious).Row & ")"), newColumnOrder)
End Sub
Run Code Online (Sandbox Code Playgroud)
另外,是否可以修改此代码以使用已使用 VBA 创建的表?我一直在试图找出一种重新排列 ListColumns 的方法,但似乎最好的选择是重新排列实际的字母/数字列。
谢谢!
无论谁写下这句话,当他们完成时,一定像一个疯狂的科学家一样笑起来。它结合了许多函数和方法,可以在一行中执行整个子代码。我将尝试解释每一步。
Range("A1"):从单元格 A1 开始,因此范围可以从此顶角延伸以抓取工作表的其余部分。
.Resize(Range("A1"):这是将从单个单元格延伸到包含目标区域的属性。Resize 有两个参数:行和列,它们决定最终范围的大小。
Cells.Find("*", , xlFormulas, , xlRows, xlPrevious).Row:此.Find方法搜索Cells工作表中的所有单元格。它正在寻找*什么意味着什么。它指定xlPrevious这意味着它正在向后搜索。但由于它正在搜索所有单元格,因此它是从右下角到左上角搜索。这是查找工作表底行的快速方法。
.Row:这将从结果中获取行#,.Find该行将成为工作表的底行。
UBound(newColumnOrder) + 1:计算数组内的项目数newColumnOrder。由于使用从 0 开始定义的数组Array(),因此需要在上限上加 1 来获取计数。
Resize(:现在回到这个属性,我们已经理解了输入参数,我们正在调整Range("A1")大小以从“A1”扩展到等于数组大小的列数newColumnOrder和足够的行来包含工作表的所有非空白单元格。
= Application.Index(:索引函数返回单个值,但由于我们将此值分配给多单元格区域,VBA 自动将此解释为“对区域中的每个单元格执行此操作”。当将公式值应用到范围中时,VBA 也很智能,可以自动调整引用以遵循当前单元格的地址。这就是函数“迭代”数组newColumnOrder而不实际循环的方式。
Cells: 的第一个参数Index。Excel 将从这里获取值。Cells是工作表上的所有单元格。值得注意的是,由于单元格也从“A1”开始,因此该范围与我们的目标范围之间没有偏移。如果将其替换为不同的范围,请确保考虑 的其他两个参数的偏移量Index。
Evaluate(:函数的第二个参数Index是要从第一个参数定义的范围返回的值的行号。该Evaluate方法要求 VBA 解释输入表达式,类似于 Excel 工作表计算输入公式/引用的方式。这用于将作为 Excel 公式的输入字符串转换为值数组。
"ROW(1:" __ ")":这是 Excel 中的 ROW 函数,它返回输入引用中的行#。由于输入是一个范围而不是单个引用,因此我们得到与该范围中每个单元格的 ROW # 相对应的值数组。当 VBA 用函数的结果填充我们的目标范围时Index,它将自动“迭代”该数组。这将输入到Index与每个单元格当前行#相对应的行#,因为填充的目标范围和索引范围之间没有偏移。
Cells.Find("*", , xlFormulas, , xlRows, xlPrevious).Row:与上面相同,这是工作表最底部单元格的行号。
newColumnOrder:的第三个参数Index是要求列号。我们不是输入单个值,而是输入整个数组。与在范围内自动填充公式时单元格引用如何自动移动类似,VBA 在填充范围时会迭代数组,并直接从中获取列号。因此,我们的目标范围的第一列将从数组的第一个元素中的列 # 填充,第二列将从数组的第二个元素中的列 # 填充。
结论:
该行表示“进入从 A1 开始延伸到数组大小newColumnOrder和工作表最后填充的行的范围。用同一行中的单元格的值重新填充每个单元格,但其列 # 可以在newColumnOrder数组的索引是您当前的列号。”
为了回答关于如何为不同的表编写此代码的第二个问题,我建议您不要编写这样的代码。虽然它可能是代码高尔夫获胜者,因为它是完成任务的最少行数,但它很神秘且难以阅读或编辑。相反,我建议类似于以下的代码:
Sub ReOrderingColumnsExample()
'Define the desired column order
Dim newColumnOrder() As Variant
newColumnOrder = Array(1, 3, 5, 2, 4, 6)
'Define the output range, manually or dynamically
Dim OutputRange As Range
Set OutputRange = Sheet1.Range("A1:F20")
'Define the input range, manually or dynamically
Dim InputRange As Range
Set InputRange = Sheet1.Range("R34:W53")
'Create an array to hold the columns
Dim ColArrs() As Variant
ReDim ColArrs(1 To InputRange.Columns.Count)
'Fill the array with arrays of each column's values
Dim i As Long
For i = 1 To InputRange.Columns.Count
ColArrs(i) = InputRange.Columns(i).Value
Next i
'Output the arrays into the output range with the column based on newColumnOrder
For i = 1 To OutputRange.Columns.Count
OutputRange.Columns(i) = ColArrs(newColumnOrder(i - 1))
Next i
End Sub
Run Code Online (Sandbox Code Playgroud)
明显减少了混乱,并且所有部分都可以轻松编辑以适合您的特定参数。