Как сгенерировать алфавитно-цифровое c дерево изменений с критериями? - PullRequest
0 голосов
/ 07 августа 2020

Я работаю над шаблоном листа Excel, используемым для системы SAP, и у меня есть 2 столбца, как показано ниже:

Column C               Column E
Level                  Element Code
3                      ABCD.01.01.01               
4                      ABCD.01.01.01.01
4                      ABCD.01.01.01.02
4                      ABCD.01.01.01.03
3                      ABCD.01.01.02
4                      ABCD.01.01.02.01 'I Want to Restart Numbering Here
4                      ABCD.01.01.02.02
4                      ABCD.01.01.02.03

Мне удалось автоматизировать уровень 3 на всем листе с помощью макроса, как показано ниже

Sub AutoNumber3()

Dim Rng, C As Range
Dim Lrow As Long
Dim i As Integer
Lrow = Cells(Rows.Count, 1).End(xlUp).Row
Set Rng = Worksheets("Union").Range("C2:C" & Lrow)
i = 1
For Each C In Rng.Cells
If C.Value = 3 Then
For i = 1 To i Step 1
C.Offset(0, 2).Value = "ABCD.01.01." & i
Next i
End If
Next C
End Sub

, и я использовал то же самое для уровня 4, что и ниже

Sub AutoNumber4()
Dim Rng, C As Range
Dim Lrow As Long
Dim i As Integer
Lrow = Cells(Rows.Count, 1).End(xlUp).Row
Set Rng = Worksheets("Union").Range("C2:C" & Lrow)
i = 1
For Each C In Rng.Cells
If C.Value = 4 Then
For i = 1 To i Step 1
C.Offset(0, 2).Value = "ABCD.01.01.01" & i
Next i
End If
Next C
End sub

Я хочу перезапустить нумерацию уровня 4 с 1 каждый раз, когда значения ячеек в столбце уровня = 3 на с использованием Do до следующего C .Value = 3, I = 1 Но я не могу правильно указать его в процедуре Autonumber4

Ваша помощь очень ценится, так как этот лист может достигать 50000 или 100000 строк, что является невозможно заполнить их вручную

Спасибо, С уважением

Moheb Labib

Ответы [ 2 ]

2 голосов
/ 07 августа 2020

Попробуйте это

Sub AutoNumber()
    Dim rngLevels As Range, cl As Range
    Dim lLastRow As Long, i As Long
    Dim sElemCode As String
    Dim vLevelsCounter() As Long
    
    With ThisWorkbook.Sheets("Union")
        lLastRow = Evaluate("=COUNTA(" & .Name & "!C:C)")
        lLastRow = WorksheetFunction.Max(lLastRow, .Cells(Rows.count, "C").End(xlUp).Row)
        Set rngLevels = .Range("C2:C" & lLastRow)
    End With
    
    For Each cl In rngLevels.Cells
        ' Uncomment "If" to use it on filtered data only
        'If Not cl.EntireRow.Hidden Then
            UpdateLevelsCounters vLevelsCounter, cl.Value
            
            sElemCode = "ABCD"
            For i = 1 To cl.Value
                sElemCode = sElemCode & "." & Format(vLevelsCounter(i), "00")
            Next i
            cl.Offset(0, 2).Value = sElemCode
        'End If
    Next cl
End Sub

Function UpdateLevelsCounters(ByRef arr() As Long, lLevel As Long)
    If lLevel < 1 Then Exit Function
    
    Dim i As Long
    ReDim Preserve arr(1 To lLevel)
    
    For i = LBound(arr) To lLevel - 1
        If arr(i) = 0 Then arr(i) = 1
    Next i
    arr(lLevel) = arr(lLevel) + 1
End Function

Это должно работать и для уровней, кроме 3 и 4 (надеюсь)

введите описание изображения здесь

1 голос
/ 07 августа 2020

Вы не указали, будет ли ваш счет всегда состоять из двух цифр или нет, и может ли это быть что-то вроде 01.20.99.99, но эта формула может привести вас в правильном направлении (не проверено с 100000 записями)

введите описание изображения здесь

=IF(C2=3;"ABCD.01.01."&TEXT(COUNTIF($C$2:C2;C2);"00");INDIRECT("E"&SUMPRODUCT(MAX(--($C$2:C2=3)*ROW($C$2:C2))))&"."&TEXT(SUMPRODUCT(--($C$2:C2=4)*--(ROW($C$2:C2)>SUMPRODUCT(MAX(--($C$2:C2=3)*ROW($C$2:C2)))));"00"))

Вот как это работает:

A) Сначала мы проверяем, является ли ячейка в столбце C 3 или 4. В случае 3, мы делаем ;"ABCD.01.01."&TEXT(COUNTIF($C$2:C2;C2);"00"); Это будет подсчитывать, сколько раз число 3 появляется в диапазоне $C$2:C2 и будет сцеплено со строкой ABCD.01.01. Уловка здесь заключается в использовании $C$2:C2, потому что он создает динамический диапазон c (, но это может привести к перегрузке вычислений. )

B) Если не 3, то мы делаем действительно полную часть, которую я попытаюсь объяснить. Кроме того, мы используем уловку динамики c диапазон

  1. SUMPRODUCT(MAX(--($C$2:C2=3)*ROW($C$2:C2)))) эта часть используется дважды. Он получит номер последней строки из последних 3 значений в столбце C. Пример : ROW($C$2:C6) получит массив только номеров строк, например {2;3;4;5;6}. --($C$2:C6=3) вернет массив из нуля / единицы в зависимости от того, равна ли ячейка / не равна 3, что-то вроде {1;0;0;0;1}. ($C$2:C6=3)*ROW($C$2:C6)) умножит оба массива, поэтому мы получим {1;0;0;0;1}*{2;3;4;5;6}={2;0;0;0;6}. И с помощью MAX мы получаем максимальное значение из этого массива, это 6 означает последнюю позицию значения 3.
  2. Мы используем INDIRECT в сочетании с номером шага 1, чтобы получить текст внутри ячейки
  3. SUMPRODUCT(--($C$2:C2=4)*--(ROW($C$2:C2)>SUMPRODUCT(MAX(--($C$2:C2=3)*ROW($C$2:C2)))));" Все, что находится после >, является тем же logi c, что и шаг 1. Он вернет номер строки последней ячейки, содержащей 3. Часть SUMPRODUCT(--($C$2:C2=4)*--(ROW($C$2:C2) просто получит номера строк тех ячеек, которые содержат 4 значения. , и номера строк выше , чем значение, полученное на шаге 1. Таким образом вы убедитесь, как подсчитать ячейки, содержащие 4 значения, между двумя ячейками, содержащими 3 значения.
  4. Мы объединяем все для формирования окончательной строки.
  5. Функции ТЕКСТ используются только для того, чтобы вычисление было 2-значным.

Вы можете использовать это вручную или вставить формулу с помощью VBA, перетащить вниз, а затем преобразовать все в значения (я бы, вероятно, сделал это). Что-то вроде этого может сработать.

Sub Macro1()
Dim LR As Long

LR = Range("C" & Rows.Count).End(xlUp).Row 'last non blank row in column c

Range("E2").FormulaR1C1 = _
    "=IF(RC[-2]=3,""ABCD.01.01.""&TEXT(COUNTIF(R2C3:RC[-2],RC[-2]),""00""),INDIRECT(""E""&SUMPRODUCT(MAX(--(R2C3:RC[-2]=3)*ROW(R2C3:RC[-2]))))&"".""&TEXT(SUMPRODUCT(--(R2C3:RC[-2]=4)*--(ROW(R2C3:RC[-2])>SUMPRODUCT(MAX(--(R2C3:RC[-2]=3)*ROW(R2C3:RC[-2]))))),""00""))"
Range("E2").AutoFill Destination:=Range("E2:E" & LR), Type:=xlFillDefault
Range("E2:E" & LR) = Range("E2:E" & LR).Value 'paste into values
End Sub

ПРИМЕЧАНИЕ: Вероятно, вам нужно будет адаптировать это в зависимости от результатов (мы не знаем, может ли количество из 3 или 4 значений иметь 3 или 4 цифры и т. д.).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...