如何更改列排序以将整个工作表排序为不仅仅是列?

时间:2015-06-26 20:05:11

标签: excel-vba sorting quicksort vba excel

我使用底部的代码按字母顺序,数字地以及以下字母和标点字符(AB00017C)对列进行排序。在我正在研究的单一列表上,生活是美好的。只要数据在A列中,一切看起来都很棒。

当我移动到包含多个列的工作表时,它很简单!

我花了两天时间让这种方式起作用。它在A列的右侧插入3个辅助列,将单元格值从A列切割为三个新列,然后按正确顺序对它们进行排序。最后,它删除了3个辅助列。

我已将代码附加到一个简单的命令按钮进行测试。对不起,论坛已经删除了所有评论。

我的表格列在CG栏目中,这个子程序非常有用。

现在我的头疼了,我想我已经把自己编程到一个角落而且我不知道如何离开。

任何见解都会受到热烈欢迎,CraigMc

以下是一些数据

sku         post_title
AB00017a    Lixit, Glass Water Bottle, 32 oz.
AB00017     Lixit, Glass Water Bottle, 16 oz.
AB00016z    Hookbill Legume Blend with Peantus, 32 lbs.
AB00016-b   Bonito Loco Pretty Crazy Nut Blend, 32 lbs. 
AB00016     Madagascar Delite, 64 oz.
AB00017c    Nutmeats and Fruit, 32 lbs. 
AB00017g    Nutmeats and Fruit, 25 oz.

以下是代码:

Private Sub CommandButton1_Click()

    Dim intLoops    As Integer

    Dim lngNumeric  As Long
    Dim lngLastRow  As Long

    Dim rngRows     As Range
    Dim rngcell     As Range

    Dim strAlpha    As String
    Dim strPrefix   As String

    Dim strSuffix As String

    '-----------------------------
    strPrefix = "True"

    strSuffix = "False"
    '-----------------------------

    Columns("B:D").Insert Shift:=xlToRight                                      'Insert 3 temporary columns to the Right of Column A.

    lngLastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, Left("A1", 1)).End(xlUp).Row

    Set rngRows = Range("A2", Range("A" & Rows.Count).End(xlUp))                'Separates Alpha to Next Column, Numeric to the following column
        For Each rngcell In rngRows
            intLoops = Len(rngcell)                                                 'Works on one character at at time.

                For intLoops = 1 To intLoops                                    'Read each character in the cell

                    If strPrefix = "True" Then

                        If Not IsNumeric(Mid(rngcell, intLoops, 1)) Then            'This is the PREFIX

                            strAlpha = strAlpha & Mid(rngcell, intLoops, 1)

                            If IsNumeric(Mid(rngcell, intLoops + 1, 1)) Then        'Is the next character Aphabetic, Yes this is the SUFFIX coming up.

                                strPrefix = "False"                             'Next Charater is the Suffix
                            End If

                        Else
                            lngNumeric = lngNumeric & Mid(rngcell, intLoops, 1)                   'No it is the number in the middle

                         End If

                    Else                                                        'This is the Suffix

                        If IsNumeric(Mid(rngcell, intLoops, 1)) And strSuffix = "False" Then

                            lngNumeric = lngNumeric & Mid(rngcell, intLoops, 1)                   'No it is the number in the middle

                            If (Mid(rngcell, intLoops + 1, 1)) = "-" Then           'Onceyou hit a non-numeric character stay in the suffix.

                                strSuffix = "True"                              'Ensures that all that follows the center number stays in the Suffix.

                            End If

                        Else

                            alpSuffix = alpSuffix & Mid(rngcell, intLoops, 1)       'Character SUFFIX

                        End If

                    End If

                Next intLoops

            rngcell.Offset(, 1) = strAlpha
            rngcell.Offset(, 2) = lngNumeric
            rngcell.Offset(, 3) = alpSuffix & " "
            strAlpha = vbNullString
            lngNumeric = 0
            alpSuffix = vbNullString
            strPrefix = "True"
            strSuffix = "False"
        Next rngcell
    Set rngRows = rngRows.Resize(rngRows.Rows.Count, 4)

    rngRows.Sort key1:=rngRows.Range(Cells(1, 3), Cells(rngRows.Rows.Count, 3)), order1:=xlAscending, _
                 key2:=rngRows.Range(Cells(1, 2), Cells(rngRows.Rows.Count, 2)), order2:=xlAscending, Header:=xlGuess

    lngLastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, Left("A2", 1)).End(xlUp).Row

    ActiveSheet.Sort.SortFields.Clear
    ActiveSheet.Sort.SortFields.Add Range("B1"), xlSortOnValues, xlAscending
    ActiveSheet.Sort.SortFields.Add Range("C1"), xlSortOnValues, xlAscending
    ActiveSheet.Sort.SortFields.Add Range("D1"), xlSortOnValues, xlAscending

    With ActiveSheet.Sort
        .SetRange Range("A1").CurrentRegion
        .Header = xlYes
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With

    Columns("B:D").Delete Shift:=xlToLeft                                       'Delete the 3 temporary columns to the Right of Column A.

End Sub

谢谢!

1 个答案:

答案 0 :(得分:0)

我做了一些修改以解决范围问题,但是字符串的解析效果很好

我的更改:

  • 我将主程序移至新模块
  • 我将其更改为“硕士硕士”单页
  • 将大部分变量重命名为更直观

  • 通过

    减少与工作表对象的交互
    • 将数据复制到内存,一次
    • 使用算法解析字符串

      • 但是分裂字符串是在内存中完成的,而不是单元格和范围 - 提高了性能
    • 将内存中的数据放回到工作表中,一次

  • 将排序应用于工作表上的所有数据(您的排序区域设置不正确)

  • 删除临时助手列

以下是更新后的代码,请将其放入新模块

if (true) {
  ...
}

function doSomething() {
  ...
}

将此功能放在同一个(新)模块中

 public class Test extends Thread{
   @override
   public void run(){
        //do something

   }
   public void run(int i){
        //do something

   }

  public static void main(String[] args) {
     Test test=new Test();
     // test.start()
     // How Can I let the two run() methods run in different thread?

 }

}

您可以从任何Sheet模块调用main函数,如下所示:

Option Explicit

'Place the code in a new module (from the menu: Insert -> Module)

Private Const START_COL As Byte = 1

Public Sub SortSheet(ByVal wsName As String, _
                     Optional ByVal sortCol As Long = 1, _
                     Optional ByVal row1 As Long = 2)

    Dim wb          As Workbook:    Dim ws          As Worksheet

    Dim lRow        As Long:        Dim lCol        As Long
    Dim thisRow     As Long:        Dim thisStr     As String
    Dim lastCell    As Range

    Dim sortRng     As Range:       Dim sortKey1    As Range
    Dim sortKey2    As Range:       Dim sortKey3    As Range

    Dim memArr1Col  As Variant      'column with strings         (in memory)
    Dim memArr3Col  As Variant      'helper columns, for sorting (in memory)

    Dim char        As Long:        Dim strLen      As Long
    Dim preBol      As Boolean:     Dim sufBol      As Boolean
    Dim midNum      As String
    Dim preStr      As String:      Dim sufStr      As String

    '---------------------------------------
    preBol = True
    sufBol = False
    '---------------------------------------
    With Application
        .ScreenUpdating = False
        Set wb = .ActiveWorkbook
    End With

    Set ws = Sheets(wsName)
    Set lastCell = GetMaxCell(ws.UsedRange)
    lRow = lastCell.Row
    lCol = lastCell.Column

    If row1 <= lRow Then

        With ws                             'set mem arrays: sort col, and helpers
            memArr1Col = .Range(.Cells(row1, sortCol), .Cells(lRow, sortCol))
            memArr3Col = .Range(.Cells(row1, lCol + 1), .Cells(lRow, lCol + 3))
        End With

        For thisRow = row1 - 1 To lRow - 1  'parse each cell in sort column

            If Not IsEmpty(memArr1Col(thisRow, 1)) And _
               Not IsNull(memArr1Col(thisRow, 1)) And _
               Len(memArr1Col(thisRow, 1)) > 0 Then

                thisStr = memArr1Col(thisRow, 1)
                strLen = Len(thisStr)

                For char = 1 To strLen          'parse each string
                    If preBol = True Then
                        If Not IsNumeric(Mid(thisStr, char, 1)) Then
                            preStr = preStr & Mid(thisStr, char, 1)
                            preBol = Not IsNumeric(Mid(thisStr, char + 1, 1))
                        Else
                            midNum = midNum & Mid(thisStr, char, 1)
                        End If
                    Else
                        If IsNumeric(Mid(thisStr, char, 1)) And sufBol = False Then
                            midNum = midNum & Mid(thisStr, char, 1)
                            sufBol = (Mid(thisStr, char + 1, 1)) = "-"
                        Else
                            sufStr = sufStr & Mid(thisStr, char, 1)
                        End If
                    End If
                Next   'Next character in the string
                memArr3Col(thisRow, 1) = preStr
                memArr3Col(thisRow, 2) = midNum
                memArr3Col(thisRow, 3) = sufStr & " "
                preBol = True
                sufBol = False
                midNum = vbNullString
                preStr = vbNullString
                sufStr = vbNullString
            End If
        Next   'Next Row

        With ws
            'place helper column values from memory to current worksheet
            .Range(.Cells(row1, lCol + 1), .Cells(lRow, lCol + 3)) = memArr3Col
            'set sort range - all data on this sheet plus the last 3 helper columns
            Set sortRng = .Range(.Cells(row1, START_COL), .Cells(lRow, lCol + 3))

            'set sort keys to helper columns
            Set sortKey1 = .Range(.Cells(row1, lCol + 1), .Cells(lRow, lCol + 1))
            Set sortKey2 = .Range(.Cells(row1, lCol + 2), .Cells(lRow, lCol + 2))
            Set sortKey3 = .Range(.Cells(row1, lCol + 3), .Cells(lRow, lCol + 3))
        End With

        With ws
            With .Sort  'apply the sort
                With .SortFields
                    .Clear
                    .Add sortKey1, xlSortOnValues, xlAscending
                    .Add sortKey2, xlSortOnValues, xlAscending
                    .Add sortKey3, xlSortOnValues, xlAscending
                End With
                .SetRange sortRng
                .Header = xlYes
                .Orientation = xlTopToBottom
                .Apply
            End With
            .Range( _
                    .Cells(row1, lCol + 1), _
                    .Cells(lRow, lCol + 3)).EntireColumn.Delete 'delete helper cols
            .Activate
            .Cells(1, 1).Activate
        End With
    End If
    Application.ScreenUpdating = True
End Sub

或者像这样(覆盖默认参数)

Public Function GetMaxCell(Optional ByRef rng As Range = Nothing) As Range

    'Returns the last cell of range with data, or A1 if Worksheet is empty

    Const NONEMPTY As String = "*"
    Dim lRow As Range, lCol As Range

    If rng Is Nothing Then Set rng = Application.ActiveWorkbook.ActiveSheet.UsedRange
    If WorksheetFunction.CountA(rng) = 0 Then
        Set GetMaxCell = rng.Parent.Cells(1, 1)
    Else
        With rng
            Set lRow = .Cells.Find(What:=NONEMPTY, LookIn:=xlFormulas, _
                                   After:=.Cells(1, 1), _
                                   SearchDirection:=xlPrevious, _
                                   SearchOrder:=xlByRows)
            If Not lRow Is Nothing Then
                Set lCol = .Cells.Find(What:=NONEMPTY, LookIn:=xlFormulas, _
                                       After:=.Cells(1, 1), _
                                       SearchDirection:=xlPrevious, _
                                       SearchOrder:=xlByColumns)

                Set GetMaxCell = .Parent.Cells(lRow.Row, lCol.Column)
            End If
        End With
    End If
End Function

要更改排序键,请相应地修改以下3行:

PreFix (第一个辅助列,然后是第2个,然后是第3个)进行排序:

Option Explicit

Private Sub CommandButton1_Click()

    SortSheet wsName:="Master of Masters"

End Sub

要排序中间身份号码(第二个辅助列,然后是第1个,然后是第3个):

Option Explicit

Private Sub CommandButton1_Click()

    SortSheet wsName:="Master of Masters", sortCol:=1, row1:=2

End Sub

要排序 PostFix (第三个辅助列,然后是第二个,然后是第三个):

Set sortKey1 = .Range(.Cells(row1, lCol + 1), .Cells(lRow, lCol + 1))   'PreFix: "AB"
Set sortKey2 = .Range(.Cells(row1, lCol + 2), .Cells(lRow, lCol + 2))   'Middle ID
Set sortKey3 = .Range(.Cells(row1, lCol + 3), .Cells(lRow, lCol + 3))   'PostFix

我使用您提供的数据对其进行了测试。结果如下:

{{0}}

排序期间 - 说明解析3个帮助列中字符串的结果

{{0}}