Excel 从单列到3X8表

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表) 下面

我在一列中有一个名字的排序列表。我想在打印之前将名称转换为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表)

下面是我得到的。很接近,但不完全正确

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
语句没有任何影响。为了进一步调查,我建议阅读以下章节