Страницы: 1
RSS
Cортировка (ранжирование) по любому количеству столбцов
 
Здравствуйте!

У меня есть массив данных в произвольном порядке в нескольких столбцах. Некоторые данные дублируются.  
Сделала сортировку в Power Query (результат на листе СВОД прикрепленного файла), но потребовалось много "ручного труда" (каждый столбец группировала в PQ, потом в Excel через копирование/ вставку объединяла).

Подскажите, пожалуйста, как еще можно сделать сортировку (ранжирование) массива данных по возрастанию и оптимизировать процесс? В примере данные массива сокращены, в оригинале в каждом столбце до 1 млн. строк.

P.S. VBA только осваиваю, соответственно, с написанием сложных макросов пока проблема.

Спасибо!
 
Добрый день!
Не нужно описывать ваши пути решения, опишите лучше задание, что есть и что нужно получить в итоге.
Вам нужно подсчитать количество каждой цифры в массиве данных?
 
Добрый день!

Что есть: массив данных в нескольких столбцах (вкладка файла "массив данных"). Задача: необходимо сделать сортировку всего массива по возрастанию. В чем сложность: в реальном примере во всех столбцах примерно по 1 млн. строк.  
 
Анна, У вас произвольное кол-во столбцов рандомных данных. Вы хотите собрать все данные в 1н столбец и отсортировать. Верно ?
 
Да, все верно.
 
выполните SortData при активной книге с данными
Код
Sub SortData()
  Dim rg As Range, crg As Range, r&, cnt&, c&, n&, v
  Worksheets(1).Copy after:=Worksheets(Worksheets.Count)
  With Worksheets(Worksheets.Count)
    Set rg = .[a1].CurrentRegion
    For Each crg In rg.Columns
      SortRg crg
    Next
    .Columns(1).Insert: On Error Resume Next: r = 1: c = 1: n = 1
    Do
      v = WorksheetFunction.Small(rg, n)
      If Err Then Exit Do
      n = n + WorksheetFunction.CountIf(rg, v)
      For Each crg In rg.Columns
        cnt = WorksheetFunction.CountIf(crg, v)
        If cnt > 0 Then
          If crg.Cells(1) = v Then f = 1 Else f = WorksheetFunction.Match(v, crg, 0)
          If .Rows.Count - r + 1 < cnt Then
            r = 1: c = c + 1: Columns(c).Insert
          End If
          .Cells(r, c).Resize(cnt, 1) = .Cells(f, crg.Column).Resize(cnt, 1).Value
          r = r + cnt
        End If
      Next
    Loop
    On Error GoTo 0
  End With
End Sub


Sub SortRg(rg As Range)
  rg.Parent.Sort.SortFields.Clear
  rg.Parent.Sort.SortFields.Add Key:=rg, _
    SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
  With rg.Parent.Sort
    .SetRange rg: .Header = xlNo: .MatchCase = False
    .Orientation = xlTopToBottom: .SortMethod = xlPinYin: .Apply
  End With
End Sub
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Код
Option Explicit

Const N = 1000000

Sub Сортировка_Более_Миллиона_Элементов()
    
    Dim sh As Worksheet
    Set sh = ActiveSheet
    
    Dim r As Range
    Set r = sh.Range("A1:E34")
    
    Dim ar1 As Variant
    ar1 = r
    
    Dim ar2 As Variant
    ar2 = GetAr2(ar1)
    
    SortArr ar2
    
    ReDim ar1(1 To r.Rows.Count, 1 To r.Columns.Count)
    FillAr1 ar1, ar2
        
    OutAr1 ar1
End Sub

Sub OutAr1(arr As Variant)
    Dim wb As Workbook
    Dim sh As Worksheet
    Set wb = Workbooks.Add(1)
    Set sh = wb.Sheets(1)
    sh.Cells(1, 1).Resize(UBound(arr, 1), UBound(arr, 2)) = arr
End Sub

Sub FillAr1(ar1 As Variant, ar2 As Variant)
    Dim y As Long
    Dim u As Long
    Dim x As Integer
    Dim h As Integer
    
    u = 1
    h = 1
    For x = 1 To UBound(ar2, 2)
    For y = 1 To UBound(ar2, 1)
        ar1(u, h) = ar2(y, x)
        u = u + 1
        If u > UBound(ar1, 1) Then
            u = 1
            If h < UBound(ar1, 2) Then h = h + 1
        End If
    Next
    Next
    
End Sub

Sub SortArr(ByRef arr As Variant)
    
    Dim wb As Workbook
    Set wb = Workbooks.Add(1)
    Dim sh As Worksheet
    Set sh = wb.Sheets(1)
    
    Dim x As Integer
    With sh
        For x = 1 To UBound(arr)
            .Cells(1, x).Resize(N, 1) = arr(x)
        Next
    End With
    
    Dim r1 As Range
    Dim r2 As Range
    Dim ar1 As Variant
    Dim ar2 As Variant
    Dim y As Long
    Dim bExit As Boolean
    Dim n2 As Long
    Dim y2 As Long
    'y = N / 2
    
    Do
        
        For x = 1 To UBound(arr)
            With sh.Sort
                .SortFields.Clear
                .SortFields.Add Key:=Cells(1, x).Resize(N), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
                .SetRange Cells(1, x).Resize(N): .Header = xlGuess: .MatchCase = False: .Orientation = xlTopToBottom: .SortMethod = xlPinYin
                .Apply
            End With
        Next
        
        With sh
            bExit = True
            For x = 1 To UBound(arr) - 1
            If Not IsEmpty(.Cells(1, x + 1).Value) Then
                y = 0
                On Error Resume Next
                y = WorksheetFunction.Match(.Cells(1, x + 1).Value, .Cells(1, x).Resize(N), 1)
                On Error GoTo 0
                y = y + 1
                
                If y <= N Then
                    n2 = WorksheetFunction.CountA(.Cells(1, x + 1).Resize(N))
                    y2 = y + n2 - 1
                    If y2 > N Then y2 = N
                
                    Set r1 = .Range(.Cells(y, x), .Cells(y2, x))
                    Set r2 = .Cells(1, x + 1).Resize(r1.Rows.Count)
                    
'                    r1.Select
'                    r2.Select
                    
                    ar1 = r1
                    ar2 = r2
                    
                    r1 = ar2
                    Erase ar2
                    r2 = ar1
                    Erase ar1
                    
                    bExit = False
                    'Exit For
                    If r1.Rows.Count <> N Then
                        With sh.Sort
                            .SortFields.Clear
                            .SortFields.Add Key:=Cells(1, x + 1).Resize(N), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
                            .SetRange Cells(1, x + 1).Resize(N): .Header = xlGuess: .MatchCase = False: .Orientation = xlTopToBottom: .SortMethod = xlPinYin
                            .Apply
                        End With
                    End If
                End If
            End If
            Next
        End With
        
        If bExit Then Exit Do
    Loop
    
    With sh
        x = UBound(arr)
        arr = .Range(.Cells(1, 1), .Cells(N, x))
    End With

    wb.Saved = True
    wb.Close

End Sub

Function GetAr2(arr As Variant) As Variant
    Dim y As Long
    Dim x As Integer
    
    y = UBound(arr, 1) * UBound(arr, 2) / N
    y = y + 1
    
    Dim ar3 As Variant
    ReDim ar3(1 To N, 1 To 1)
    Dim ar2 As Variant
    ReDim ar2(1 To y)
    For y = 1 To UBound(ar2)
        ar2(y) = ar3
    Next
    Erase ar3
    
    Dim u As Long
    Dim h As Long
    h = 1
    u = 1
    For x = 1 To UBound(arr, 2)
    For y = 1 To UBound(arr, 1)
        ar2(h)(u, 1) = arr(y, x)
        u = u + 1
        If u > N Then
            u = 1
            h = h + 1
        End If
    Next
    Next
    
    GetAr2 = ar2
End Function
 
Немного подкрутила макрос по диапазону и все работает отлично. Спасибо всем большое за помощь!
Страницы: 1
Наверх