Excel 从单列到3X8表
我在一列中有一个名字的排序列表。我想在打印之前将名称转换为3X8表(打印单列会占用太多纸张)。这是Excel。我会一个接一个地复制名字,然后粘贴到一张空白纸上 以数字为例,生成的顺序应如下所示:Excel 从单列到3X8表,excel,vba,algorithm,Excel,Vba,Algorithm,我在一列中有一个名字的排序列表。我想在打印之前将名称转换为3X8表(打印单列会占用太多纸张)。这是Excel。我会一个接一个地复制名字,然后粘贴到一张空白纸上 以数字为例,生成的顺序应如下所示: 1 9 17 2 10 18 3 11 19 4 12 20 5 13 21 6 14 22 7 15 23 8 16 24 25 33 41 26 34 42 27 35 43 ........ 是否可能得到一般答案(n x m表) 下面
1 9 17
2 10 18
3 11 19
4 12 20
5 13 21
6 14 22
7 15 23
8 16 24
25 33 41
26 34 42
27 35 43
........
是否可能得到一般答案(n x m表)
下面是我得到的。很接近,但不完全正确
last_row = ThisWorkbook.Sheets(1).Cells(20000,1).End(xlUp).Row
For i = 1 To last_row/24 +1 Step 1
For k = 1 To 3 Step 1
For j = 1 To members_per_column Step 1
ThisWorkbook.Sheets(1).Cells( i + j + (k - 1) * 8 + (i - 1) * 16 + 1, _
name_column).Copy
Worksheets(destination_page).Cells( i + j - 1, (k - 1) +1).PasteSpecial _
Paste:=xlPasteValues
Next j
Next k
Next i
我没有使用三个循环,而是使用mod使用一个循环在正确的位置写入 作为作者,我觉得这似乎很明显,但如果不清楚,请提问——这有助于下一位读者
Option Explicit
Sub ColumnSplit()
Dim input_rows As Integer
Dim output_columns As Integer
Dim output_rows As Integer
Dim i As Integer
Dim input_sheet As Worksheet
Dim output_sheet As Worksheet
Set input_sheet = Sheet1
Set output_sheet = Sheet2
'output_sheet.Cells.Clear 'optional
output_columns = 3 'Hard coded. Set to whatever you like
input_rows = input_sheet.Cells(Rows.Count, 1).End(xlUp).Row
output_rows = CInt(WorksheetFunction.Ceiling(CDbl(input_rows) / CDbl(output_columns), 1))
For i = 1 To input_rows
output_sheet.Cells( _
((i - 1) Mod output_rows) + 1 _
, (WorksheetFunction.Floor((i - 1) / output_rows, 1) Mod output_columns) + 1 _
) _
= input_sheet.Cells(i, 1) 'cells(calculate output row,calculate output column) = input value
Next i
End Sub
我没有使用三个循环,而是使用mod使用一个循环在正确的位置写入 作为作者,我觉得这似乎很明显,但如果不清楚,请提问——这有助于下一位读者
Option Explicit
Sub ColumnSplit()
Dim input_rows As Integer
Dim output_columns As Integer
Dim output_rows As Integer
Dim i As Integer
Dim input_sheet As Worksheet
Dim output_sheet As Worksheet
Set input_sheet = Sheet1
Set output_sheet = Sheet2
'output_sheet.Cells.Clear 'optional
output_columns = 3 'Hard coded. Set to whatever you like
input_rows = input_sheet.Cells(Rows.Count, 1).End(xlUp).Row
output_rows = CInt(WorksheetFunction.Ceiling(CDbl(input_rows) / CDbl(output_columns), 1))
For i = 1 To input_rows
output_sheet.Cells( _
((i - 1) Mod output_rows) + 1 _
, (WorksheetFunction.Floor((i - 1) / output_rows, 1) Mod output_columns) + 1 _
) _
= input_sheet.Cells(i, 1) 'cells(calculate output row,calculate output column) = input value
Next i
End Sub
你已经很接近了。我将代码包装到一个函数中,以便您可以轻松地在任何矩阵大小上重复使用它:
Option Explicit
Public Sub TransformIntoBlocks(ByVal MatrixRows As Long, ByVal MatrixColumns As Long, ByVal SourceRange As Range, ByVal OutputStartRange As Range)
Dim BlockStartRow As Long
BlockStartRow = 1
Dim iRowSource As Long
iRowSource = 1
Dim AmountOfBlocks As Long
AmountOfBlocks = WorksheetFunction.RoundUp(SourceRange.Rows.Count / (MatrixRows * MatrixColumns), 0)
Dim iBlock As Long
For iBlock = 1 To AmountOfBlocks
Dim iCol As Long
For iCol = 1 To MatrixColumns
Dim iRow As Long
For iRow = BlockStartRow To BlockStartRow + MatrixRows - 1
OutputStartRange.Offset(iRow - 1, iCol - 1).Value = SourceRange(iRowSource, 1).Value
iRowSource = iRowSource + 1
Next iRow
Next iCol
BlockStartRow = BlockStartRow + MatrixRows
Next iBlock
End Sub
Sub test()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
TransformIntoBlocks MatrixRows:=8, MatrixColumns:=3, SourceRange:=ws.Range("A1", ws.Cells(ws.Rows.Count, "A").End(xlUp)), OutputStartRange:=Tabelle2.Range("C1")
End Sub
你已经很接近了。我将代码包装到一个函数中,以便您可以轻松地在任何矩阵大小上重复使用它:
Option Explicit
Public Sub TransformIntoBlocks(ByVal MatrixRows As Long, ByVal MatrixColumns As Long, ByVal SourceRange As Range, ByVal OutputStartRange As Range)
Dim BlockStartRow As Long
BlockStartRow = 1
Dim iRowSource As Long
iRowSource = 1
Dim AmountOfBlocks As Long
AmountOfBlocks = WorksheetFunction.RoundUp(SourceRange.Rows.Count / (MatrixRows * MatrixColumns), 0)
Dim iBlock As Long
For iBlock = 1 To AmountOfBlocks
Dim iCol As Long
For iCol = 1 To MatrixColumns
Dim iRow As Long
For iRow = BlockStartRow To BlockStartRow + MatrixRows - 1
OutputStartRange.Offset(iRow - 1, iCol - 1).Value = SourceRange(iRowSource, 1).Value
iRowSource = iRowSource + 1
Next iRow
Next iCol
BlockStartRow = BlockStartRow + MatrixRows
Next iBlock
End Sub
Sub test()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
TransformIntoBlocks MatrixRows:=8, MatrixColumns:=3, SourceRange:=ws.Range("A1", ws.Cells(ws.Rows.Count, "A").End(xlUp)), OutputStartRange:=Tabelle2.Range("C1")
End Sub
太好了!这就是我想要的,一种完全不同的方法。但是,它没有提供3x8个表。3x8表有24个元素。所以,第一列应该从1到8,然后从25到32,就像这样:1,2,3,4,5,6,7,8,25,26,27,28,29,30,31,32(见上面的例子)。现在,它从1到页面底部,比如说40,然后第二列从41到80,第三列从81开始。我想它需要另一个循环?哈哈,是的,误读了预期的结果。Pᴇʜ的结果是有效的,只要把tabelle换成sheet就行了。太棒了!这就是我想要的,一种完全不同的方法。但是,它没有提供3x8个表。3x8表有24个元素。所以,第一列应该从1到8,然后从25到32,就像这样:1,2,3,4,5,6,7,8,25,26,27,28,29,30,31,32(见上面的例子)。现在,它从1到页面底部,比如说40,然后第二列从41到80,第三列从81开始。我想它需要另一个循环?哈哈,是的,误读了预期的结果。Pᴇʜ的结果无论如何都是有效的,只需将tabelle更改为sheet。我想知道为什么要将iCol和iRow声明为循环内部而不是外部。首先,在VBA中,无论是在循环内部还是外部声明它都无关紧要,因为VBA无论如何都会将其范围限定到过程。但是由于可维护性的原因,有充分的理由将声明放在尽可能接近第一次使用变量的位置。首先,它提高了可读性,其次,它提高了可维护性和将来的重构(例如,如果您想稍后将该循环移动到函数中,则由于变量已经紧挨着循环,因此它会更容易实现)……第三,它防止在每个过程的开头都有一大块声明。如果你不再使用变量(因为你删除了一些代码),你很容易忘记删除变量声明(删除的代码),如果它是在一开始。第四,我习惯于声明尽可能接近其用途的变量,因为在其他语言中(例如在VB.NET中),它会将变量
iCol
和iRow
的范围限定到它们的外循环。只有在您真正需要的范围内才有变量,这是一个很好的实践所以这里只是表面和编码风格的原因。当声明在循环中时,变量会被多次声明吗?这种想法使我无法在循环中声明变量。@joehua不用担心,当过程开始时,VBA做的第一件事就是创建所有已声明的变量。因此,循环对Dim
语句没有任何影响。为了进一步研究,我建议阅读以下部分,我想知道为什么要在循环内声明iCol和iRow而不是在循环外声明。首先,在VBA中,无论是在循环内还是循环外声明iCol和iRow,VBA都会将其范围限定到过程中。但是由于可维护性的原因,有充分的理由将声明放在尽可能接近第一次使用变量的位置。首先,它提高了可读性,其次,它提高了可维护性和将来的重构(例如,如果您想稍后将该循环移动到函数中,则由于变量已经紧挨着循环,因此它会更容易实现)……第三,它防止在每个过程的开头都有一大块声明。如果你不再使用变量(因为你删除了一些代码),你很容易忘记删除变量声明(删除的代码),如果它是在一开始。第四,我习惯于声明尽可能接近其用途的变量,因为在其他语言中(例如在VB.NET中),它会将变量iCol
和iRow
的范围限定到它们的外循环。只有在您真正需要的范围内才有变量,这是一个很好的实践所以这里只是表面和编码风格的原因。当声明在循环中时,变量会被多次声明吗?这种想法使我无法在循环中声明变量。@joehua不用担心,当过程开始时,VBA做的第一件事就是创建所有已声明的变量。因此,循环对Dim
语句没有任何影响。为了进一步调查,我建议阅读以下章节