Вложенный вариант выбора для нескольких условий

Ситуация: у меня есть код, который просматривает некоторые данные на листе и, учитывая то, что находится в определенной ячейке, вставляет что-то в другой столбец (та же строка).

Пример: если мой A5 является "Bond", он объединяет содержимое A5 и B5 и вставляет его в J5.

Obs1: существуют десятки подусловий для первого, второго, третьего и четвертого столбцов данных.

Что я пробовал до сих пор: мне удалось создать очень длинную вложенную цепочку "если" и учесть все условия. Я также смог использовать Select case для учета условий первого столбца.

Проблема. Теперь я пытаюсь использовать вложенный выбор регистра для учета этих условий (учитывая, что цепочка If огромна и слишком длинна, чтобы быть эффективной). Проблема в том, что я не могу правильно учитывать вложенные выборочные случаи для нескольких условий.

Вопрос. Как лучше всего работать с вложенным выбором варианта при наличии нескольких условий?

Obs2: Из предыдущего исследования я нашел здесь сообщения о вложенных if, особенно когда есть значение true или false. У меня это не работает, потому что у каждого слоя гораздо больше условий.

Код 1: вот что я получил, используя Select Case:

Function fxr2()

Dim lRow As Long, LastRow As Long
Dim w As Workbook
Dim ws As Worksheet

Set w = ThisWorkbook

Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual

LastRow = Worksheets("Fixer").Cells(Rows.Count, "A").End(xlUp).Row

For lRow = 7 To LastRow

Dim type1 As String, result As String
type1 = w.Worksheets("Fixer").Cells(lRow, 1).Text

Select Case type1
Case Is = "Bail-in"
    result = w.Worksheets("Fixer").Cells(lRow, 1)
Case Is = "Basel"
    result = w.Worksheets("Fixer").Cells(lRow, 1) & " " & w.Worksheets("Fixer").Cells(lRow, 2) & " " & w.Worksheets("Fixer").Cells(lRow, 3) & " " & w.Worksheets("Fixer").Cells(lRow, 4) & " " & w.Worksheets("Fixer").Cells(lRow, 5)
Case Is = "Collateral"
    result = w.Worksheets("Fixer").Cells(lRow, 1) & " " & w.Worksheets("Fixer").Cells(lRow, 2) & " " & w.Worksheets("Fixer").Cells(lRow, 3)
Case Is = "Design"
    result = w.Worksheets("Fixer").Cells(lRow, 1)
Case Is = "General"
    result = w.Worksheets("Fixer").Cells(lRow, 1) & " " & w.Worksheets("Fixer").Cells(lRow, 2) & " " & w.Worksheets("Fixer").Cells(lRow, 3)
Case Is = "Investment"
    result = w.Worksheets("Fixer").Cells(lRow, 1)
Case Is = "Lower"
    result = w.Worksheets("Fixer").Cells(lRow, 1) & " " & w.Worksheets("Fixer").Cells(lRow, 2) & " " & w.Worksheets("Fixer").Cells(lRow, 3)
Case Is = "Recapitalization"
    result = w.Worksheets("Fixer").Cells(lRow, 1)
Case Is = "Refinance"
    result = w.Worksheets("Fixer").Cells(lRow, 1)
Case Is = "Upper"
    result = w.Worksheets("Fixer").Cells(lRow, 1) & " " & w.Worksheets("Fixer").Cells(lRow, 2) & " " & w.Worksheets("Fixer").Cells(lRow, 3)
Case Else
    result = w.Worksheets("Fixer").Cells(lRow, 1) & " " & 
w.Worksheets("Fixer").Cells(lRow, 2)
End Select

w.Worksheets("Fixer").Cells(lRow, 10).Value = result

Next lRow

End Function

Код 2. Это небольшая часть кода, где я использовал вложенные операторы If:

ElseIf w.Worksheets("Fixer").Cells(lRow, 1) = "General" Then
    w.Worksheets("Fixer").Cells(lRow, 10) = 
w.Worksheets("Fixer").Cells(lRow, 1) & " " & 
w.Worksheets("Fixer").Cells(lRow, 2) & " " & w.Worksheets("Fixer").Cells(lRow, 3)

    If w.Worksheets("Fixer").Cells(lRow, 4) = "Base" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Inte" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Tier" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "v" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Ba" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Bas" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Int" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Inte" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Inter" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Tie" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Tier-" Then
        w.Worksheets("Fixer").Cells(lRow, 11) = ""

    ElseIf w.Worksheets("Fixer").Cells(lRow, 4) = "" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Upp" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Uppe" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Upper" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "I" Or w.Worksheets("Fixer").Cells(lRow, 4) = "L" Or w.Worksheets("Fixer").Cells(lRow, 4) = "T" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "U" Then
        w.Worksheets("Fixer").Cells(lRow, 11) = ""

    ElseIf w.Worksheets("Fixer").Cells(lRow, 4) = "Design" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Inve" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Inv" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Low" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Lowe" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Proj" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Pro" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Ref" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Refi" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Stock" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Inve" Then
        w.Worksheets("Fixer").Cells(lRow, 11) = 
w.Worksheets("Fixer").Cells(lRow, 4)

    ElseIf w.Worksheets("Fixer").Cells(lRow, 4) = "LBO" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Working" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Work" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Wor" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Gre" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Gree" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Green" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Interc" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Intercom" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Intercompany" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Intermed" Then
        w.Worksheets("Fixer").Cells(lRow, 11) = 
w.Worksheets("Fixer").Cells(lRow, 4)

    ElseIf w.Worksheets("Fixer").Cells(lRow, 4) = "Low" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Lower" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "Lowe" Or 
w.Worksheets("Fixer").Cells(lRow, 4) = "No" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Pen" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Pens" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Pension" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Projec" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Project" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Refin" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Refina" Then
        w.Worksheets("Fixer").Cells(lRow, 11) = w.Worksheets("Fixer").Cells(lRow, 4)

    ElseIf w.Worksheets("Fixer").Cells(lRow, 4) = "Refinanc" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Refinance" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Stoc" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Sto" Or w.Worksheets("Fixer").Cells(lRow, 4) = "w" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Wor" Or w.Worksheets("Fixer").Cells(lRow, 4) = "W" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Tier-1" Or w.Worksheets("Fixer").Cells(lRow, 4) = "Tier-2" Then
        w.Worksheets("Fixer").Cells(lRow, 11) = w.Worksheets("Fixer").Cells(lRow, 4)

    End If

Obs3: чтобы лучше объяснить, как организованы мои данные, вот небольшая их часть. Пример данных


person DGMS89    schedule 13.04.2017    source источник
comment
Многие из ваших дел делают то же самое. Вы можете комбинировать их следующим образом: Case "Collateral", "General", "Lower"   -  person jsheeran    schedule 13.04.2017
comment
Я не могу сказать, в чем именно ваша проблема. Это не работает или вы просто ищете более эффективный способ сделать что-то?   -  person SJR    schedule 13.04.2017
comment
@jsheeran Действительно, вы правы, моя проблема в том, что каждый из них может вызывать разные условия для последующих столбцов. Например, «Общий» объединяет A5, B5 и C5 и влияет на содержимое в D4, тогда как «Сопутствующий» объединяет A5 и B5 и не влияет на другие столбцы.   -  person DGMS89    schedule 13.04.2017
comment
@SJR Я смог сделать это с помощью Ifs, а не с Select Case. Но я не могу выполнить подусловия.   -  person DGMS89    schedule 13.04.2017
comment
Не уверен, что стоит пытаться полностью исключить If. Вы можете сделать свой код более читабельным, используя предложения With или назначив свой лист переменной.   -  person SJR    schedule 13.04.2017
comment
@SJR Действительно, это отличная идея, она сделает код более управляемым. Но с точки зрения размера, не лучше ли в такой ситуации работать с Select Case? (чтобы избежать цепочки If)   -  person DGMS89    schedule 13.04.2017
comment
Я думаю, что главное преимущество Select Case в том, что он приятнее для глаз. Я сомневаюсь, что есть какое-либо преимущество в скорости, о котором можно было бы говорить (хотя другие здесь знают лучше). Уж точно не стоит связывать себя узлами, чтобы избежать Если!   -  person SJR    schedule 13.04.2017
comment
Разве вы не можете использовать подстановочный знак во вложенных ifs? Например, In* для Int, Inte, Inter и Ti* для Tie, Tier, Tier-   -  person Luuklag    schedule 13.04.2017
comment
@Luuklag В некоторых случаях да, это возможно. Но в некоторых других случаях это не работает, например: уровень может быть либо уровнем 1, либо уровнем 2. Или для In, он может быть международным или межбанковским, так что это зависит.   -  person DGMS89    schedule 13.04.2017


Ответы (3)


Часть 1 (Код 1) вашего сообщения может выглядеть как более короткая и упрощенная версия ниже (пояснение в комментариях к коду):

Function fxr2()

Dim lRow As Long, LastRow As Long
Dim w As Workbook
Dim ws As Worksheet

Set w = ThisWorkbook
Set ws = w.Worksheets("Fixer") '<-- set the worksheet

Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual

Dim type1 As String, result As String '<-- There's no need to Dim them every time inside the loop

' use With statement, will simplify and shorten your code later
With ws
    LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row '<-- fully qualify Rows.Count with "Fixer" sheet

    For lRow = 7 To LastRow
        type1 = .Cells(lRow, 1).Text

        Select Case type1
            Case "Bail-in", "Investment", "Recapitalization", "Refinance", "Design"
                result = .Cells(lRow, 1)

            Case "Basel"
                result = .Cells(lRow, 1) & " " & .Cells(lRow, 2) & " " & .Cells(lRow, 3) & " " & .Cells(lRow, 4) & " " & .Cells(lRow, 5)

            Case "Collateral", "General", "Lower", "Upper"
                result = .Cells(lRow, 1) & " " & .Cells(lRow, 2) & " " & .Cells(lRow, 3)

            Case Else
                result = .Cells(lRow, 1) & " " & .Cells(lRow, 2)

        End Select

        .Cells(lRow, 10).Value = result
    Next lRow
End With

End Function

Все, что у вас есть ниже в коде 2, — это 2 Case условия, составленные из нескольких String, с которыми вы пытаетесь сравнить:

Select Case .Cells(lRow, 4)
    Case "Base", "Inte", "Tier", "v", "Ba", "Bas", "Int", "Inte", "Inter", "Tie", "Tier-", "", "Upp", "Uppe", "Upper", "I", "L", "T"
        .Cells(lRow, 11) = ""

    Case "Design", "Inve", "Inv", "Low", "Lowe", "Proj", "Pro", "Ref", "Refi", "Refin", "Refina", "Refinanc", "Refinance", "Stock", "Inve", "LBO", "Working", "Work", "Wor", "Gre", _
             "Gree", "Green", "Interc", "Intercom", "Intercompany", "Intermed", "Refinanc", "Stoc", "No", "Pen", "Pens", "Pension", "Projec", "Project", _
             "Sto", "Stoc", "w", "Wor", "Tier-1", "Tier-2"
        .Cells(lRow, 11) = .Cells(lRow, 4)

End Select

Не уверен, что это именно то место, куда вы хотите его поместить, но это просто пример того, как использовать Select Case, вложенный в другой Select Case.

Отредактированный "объединенный" код

Function fxr2()

Dim lRow As Long, LastRow As Long
Dim w As Workbook
Dim ws As Worksheet

Set w = ThisWorkbook
Set ws = w.Worksheets("Fixer") '<-- set the worksheet

Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual

Dim type1 As String, result As String '<-- There's no need to Dim them every time inside the loop

' use With statement, will simplify and shorten your code later
With ws
    LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row '<-- fully qualify Rows.Count with "Fixer" sheet

    For lRow = 7 To LastRow
        type1 = .Cells(lRow, 1).Text

        Select Case type1
            Case "Bail-in", "Investment", "Recapitalization", "Refinance", "Design"
                .Cells(lRow, 10).Value = .Cells(lRow, 1)

            Case "Basel"
                .Cells(lRow, 10).Value = .Cells(lRow, 1) & " " & .Cells(lRow, 2) & " " & .Cells(lRow, 3) & " " & .Cells(lRow, 4) & " " & .Cells(lRow, 5)

            Case "Collateral", "General", "Lower", "Upper"
                .Cells(lRow, 10).Value = .Cells(lRow, 1) & " " & .Cells(lRow, 2) & " " & .Cells(lRow, 3)

                ' ===== Added the Nested case here (just for example) =====
                 Select Case .Cells(lRow, 4)
                    Case "Base", "Inte", "Tier", "v", "Ba", "Bas", "Int", "Inte", "Inter", "Tie", "Tier-", "", "Upp", "Uppe", "Upper", "I", "L", "T"
                        .Cells(lRow, 11) = ""

                    Case "Design", "Inve", "Inv", "Low", "Lowe", "Proj", "Pro", "Ref", "Refi", "Refin", "Refina", "Refinanc", "Refinance", "Stock", "Inve", "LBO", "Working", "Work", "Wor", "Gre", _
                             "Gree", "Green", "Interc", "Intercom", "Intercompany", "Intermed", "Refinanc", "Stoc", "No", "Pen", "Pens", "Pension", "Projec", "Project", _
                             "Sto", "Stoc", "w", "Wor", "Tier-1", "Tier-2"
                        .Cells(lRow, 11) = .Cells(lRow, 4)

                End Select
                ' ==== End of Nested Select Case ====

            Case Else
                .Cells(lRow, 10).Value = .Cells(lRow, 1) & " " & .Cells(lRow, 2)

        End Select
    Next lRow
End With

End Function
person Shai Rado    schedule 13.04.2017
comment
Спасибо за ответ. Действительно, использование with и другие изменения, которые вы предложили, безусловно, делают код более управляемым. Но как я могу использовать дополнительные условия в каждом случае выбора (исходный вопрос)? - person DGMS89; 13.04.2017
comment
@ DGMS89, где должен быть w.Worksheets("Fixer").Cells(lRow, 4)? внутри Select Case type1, как в сочетании? или после? - person Shai Rado; 13.04.2017
comment
@ DGMS89 DGMS89 смотрите мой отредактированный ответ, так что теперь вопрос в том, где вы хотите разместить эти условия? внутри первого Select Case ? или это разные критерии? - person Shai Rado; 13.04.2017
comment
да. Например, как у меня в code2: выберите case1, где у меня есть General в A5, затем объедините A5, B5 и C5; после этого, все еще внутри этого кейса, выберите вариант 1.1, где D5 — это инвестиции (затем сделайте что-нибудь), или выберите вариант 1.2, где D5 — это уровень (затем сделайте что-нибудь еще), для каждого начального случая (скажем, начальный случай условие для столбца 1), есть подслучаи. Извините, если не можете объяснить это лучше. - person DGMS89; 13.04.2017
comment
Спасибо за помощь, это именно то, что мне было нужно. - person DGMS89; 13.04.2017

Case может быть вложен таким же образом, как IF:

Select Case a
    Case 10
        Select Case b
            Case 1
                'a is 10, b is 1
            Case 2
                'a is 10, b is 2
            Case 3
                'a is 10, b is 3
        End Select
    Case 20
        Select Case b
            Case 1
                'a is 20, b is 1
            Case 2
                'a is 20, b is 2
            Case 3
                'a is 20, b is 3
        End Select
End Select
person CLR    schedule 13.04.2017

Вероятно, это не то, что вы ожидали в качестве ответа, но логика работает безупречно, если вы примените ее к своему делу.

Предположим, что Microsoft регулярно обновляла VBA. По крайней мере так же часто, как C#. Тогда у нас было бы что-то под названием [FLAGS], и эта задача была бы очень простой. Однако у нас его нет, поэтому мы должны построить что-то подобное в одиночку.

Представьте, что у вас есть 7 продуктов (AAA, BBB, CCC, DDD, EEE, FFF, GGG) и вы хотите знать, какой из них вы выбрали. Я предполагаю, что это ядро ​​​​вашей проблемы. Это довольно просто, если использовать бинарную математику: тогда первому произведению присваивается значение 1, второму — 2, третьему — 4, четвертому — 8 и т. д.

  • 27 означает, что вы выбрали 1+2+8+16. (ААА, ВВВ, DDD, ЕЕЕ)
  • 28 означает, что вы выбрали 4+8+16. (CCC, DDD, EEE)

Таким образом, если представить, что у вас есть номер и вы хотите продукты, то что-то вроде этого может сработать. Число — это lngNumber, а LngToBinary дает вам двоичное значение числа. В Sub TestMe вместо того, чтобы печатать продукты, вы можете выполнять с ними какие-то действия.

Option Explicit
Option Private Module

Public Sub TestMe()

    Dim arrProducts     As Variant
    Dim lngCounter      As Long
    Dim lngValue        As Long
    Dim strBinary       As String
    Dim lngNumber       As Long

    arrProducts = Array("AAA", "BBB", "CCC", "DDD", "EEE", "FFF", "GGG")
                           '1,     2,     4,     8,    16,    32,    64
    lngNumber = 28 '1+2+8+16
    strBinary = StrReverse(LngToBinary(lngNumber))

    For lngCounter = 1 To Len(strBinary)
        lngValue = Mid(strBinary, lngCounter, 1)

        If lngValue Then
            Debug.Print arrProducts(lngCounter - 1)
        End If

    Next lngCounter

End Sub

Function LngToBinary(ByVal n As Long) As String

    Dim k As Long

    LngToBinary = vbNullString

    If n < -2 ^ 15 Then
        LngToBinary = "0"
        n = n + 2 ^ 16
        k = 2 ^ 14

    ElseIf n < 0 Then

        LngToBinary = "1"
        n = n + 2 ^ 15
        k = 2 ^ 14

    Else

        k = 2 ^ 15

    End If

    Do While k >= 1
        LngToBinary = LngToBinary & Fix(n / k)
        n = n - k * Fix(n / k)
        k = k / 2
    Loop

End Function

Подробнее о [FLAGS] здесь: https://msdn.microsoft.com/en-us/library/system.flagsattribute(v=vs.110).aspx

person Vityata    schedule 13.04.2017