Объединить значения на основе нескольких критериев - PullRequest
0 голосов
/ 15 января 2019

У меня есть следующий набор данных

Key ID  Status 1    Status 2    Order ID
1   A1  FALSE        TRUE     1234-USF-0025
1   A1  FALSE        TRUE     1234-USF-0026
1   A1  FALSE        TRUE     1234-USF-0027
2   A1  TRUE         TRUE     1234-USF-0025
2   A1  TRUE         TRUE     1234-USF-0026
2   A1  TRUE         TRUE     1234-USF-0027
3   A1  FALSE        TRUE     1234-USF-0025
3   A1  FALSE        TRUE     1234-USF-0026
3   A1  FALSE        TRUE     1234-USF-0027
4   A2  TRUE         TRUE     1234-USF-0028
4   A2  TRUE         TRUE     1234-USF-0029
4   A2  TRUE         TRUE     1234-USF-0030
5   A3  TRUE         TRUE     1234-USF-0031
5   A3  TRUE         TRUE     1234-USF-0032
5   A3  TRUE         TRUE     1234-USF-0033
6   A4  TRUE         TRUE     1234-USF-0034
6   A4  TRUE         TRUE     1234-USF-0035
6   A4  TRUE         TRUE     1234-USF-0036

Мне нужно следующее

Order ID        ID  TRUE    FALSE
1234-USF-0025   A1   2       1,3
1234-USF-0026   A1   2       1,3
1234-USF-0027   A1   2       1,3
1234-USF-0028   A2   4  
1234-USF-0029   A2   4  
1234-USF-0030   A2   4  
1234-USF-0031   A3   5  
1234-USF-0032   A3   5  
1234-USF-0033   A3   5  
1234-USF-0034   A4   6  
1234-USF-0035   A4   6  
1234-USF-0036   A4   6  

Во второй таблице (которая мне нужна) каждый Order ID указан рядом с соответствующим ID. Хотя A1 указан 9 раз в исходном наборе данных, всего A1 всего 3 уникальных Order IDs. Однако A1 также связан с 3 разными ключами.

Цель состоит в том, чтобы объединить Keys для каждой комбинации Order ID и ID, где оба значения Status 1 и Status 2 равны TRUE, и перечислить их в столбце TRUE. Для тех комбинаций Order ID и ID, где хотя бы один Status равен FALSE, Keys должен быть указан в столбце FALSE.

Что я пробовал

  1. Я попытался начать с только столбца TRUE, используя INDEX-MATCH в качестве формулы массива, и хотя я знаю, что приведенная ниже формула не будет работать для достижения желаемой конечной цели, я пытался начать с малого и опираться на формулу , К сожалению, мои знания о массивах ограничены, я не уверен, что делать дальше, потому что я не понимаю, почему он возвращает то, что он делает, или как достичь моей цели с этого момента.

=INDEX($C$2:$C$19,MATCH(1,($H2 = $B$2:$B$19) * ($G2 = $E$2:$E$19)))

enter image description here

  1. Затем я попытался разбить части на части в исходном наборе данных, но застрял на том, как действовать дальше. Я думаю, что это более простое решение, но я не могу понять, как объединить на основе требуемых критериев.

ИСТИНА: =IF(AND($C2=TRUE,$D2=TRUE),$A2,"")

FALSE: =IF(OR($C2<>TRUE,$D2<>TRUE),$A2,"") enter image description here

Примечания:

  • ID связан как минимум с одним Key, но может иметь больше
  • Order ID может повторяться для того же ID, но только для разных Keys для этого ID.

Я также открыт для решений на основе VBA, Python или R, но не уверен, как даже запустить сценарий для этой задачи, поэтому я сосредоточился на Excel.

Ответы [ 2 ]

0 голосов
/ 15 января 2019

Я использовал словарь и модуль класса, чтобы помочь собрать и преобразовать данные. Он также имеет то преимущество, что его легче отслеживать и поддерживать, поскольку названные параметры более или менее очевидны.

Я также «выполнил работу» в массиве VBA, так как при любой большой базе данных скорость выполнения будет значительно выше.

В коде должно быть очевидно, где определить рабочие таблицы и диапазоны, которые вы хотите использовать для исходных данных и результатов

Обычный модуль


Option Explicit
'Set reference to Microsoft Scripting Runtime
Sub orgOrders()
    Dim wsSrc As Worksheet, wsRes As Worksheet, rRes As Range
    Dim vSrc As Variant, vRes As Variant
    Dim dOrds As Dictionary, cOrd As cOrder
    Dim I As Long, V As Variant
    Dim sKey As String

'set source and result worksheet and range
Set wsSrc = Worksheets("Sheet2")
Set wsRes = Worksheets("Sheet2")
    Set rRes = wsRes.Cells(1, 10)

'read source data into array
With wsSrc
    vSrc = .Range(.Cells(1, 1), .Cells(.Rows.Count, 5).End(xlUp))
End With

'Read into order dictionary
Set dOrds = New Dictionary
For I = 2 To UBound(vSrc, 1)
    Set cOrd = New cOrder
    sKey = vSrc(I, 5) 'Order ID
    With cOrd
        .ID = vSrc(I, 2)
        .Key = vSrc(I, 1)
        .Status1 = vSrc(I, 3)
        .Status2 = vSrc(I, 4)
        .addTrueFalse .Key, .Status1, .Status2

    If Not dOrds.Exists(sKey) Then
        dOrds.Add Key:=sKey, Item:=cOrd
    Else
        dOrds(sKey).addTrueFalse .Key, .Status1, .Status2
    End If

    End With
Next I

'Dim Results array
ReDim vRes(0 To dOrds.Count, 1 To 4)

'Headers
    vRes(0, 1) = "Order ID"
    vRes(0, 2) = "ID"
    vRes(0, 3) = "TRUE"
    vRes(0, 4) = "FALSE"

'Data
I = 0
For Each V In dOrds.Keys
    I = I + 1
    With dOrds(V)
        vRes(I, 1) = V
        vRes(I, 2) = .ID
        vRes(I, 3) = .TrueFalse(True)
        vRes(I, 4) = .TrueFalse(False)
    End With
Next V

'Write results
Set rRes = rRes.Resize(UBound(vRes, 1) + 1, UBound(vRes, 2))
With rRes
    .EntireColumn.Clear
    .Value = vRes
    .Rows(1).Font.Bold = True
    With .EntireColumn
        .HorizontalAlignment = xlCenter
        .AutoFit
    End With
End With

End Sub

Модуль класса

ПЕРЕИМЕНОВАТЬ этот модуль cOrder


Option Explicit
Private pKey As Long
Private pID As String
Private pStatus1 As Boolean
Private pStatus2 As Boolean
Private pTrueFalse As Dictionary

Public Property Get Key() As Long
    Key = pKey
End Property
Public Property Let Key(Value As Long)
    pKey = Value
End Property

Public Property Get ID() As String
    ID = pID
End Property
Public Property Let ID(Value As String)
    pID = Value
End Property

Public Property Get Status1() As Boolean
    Status1 = pStatus1
End Property
Public Property Let Status1(Value As Boolean)
    pStatus1 = Value
End Property

Public Property Get Status2() As Boolean
    Status2 = pStatus2
End Property
Public Property Let Status2(Value As Boolean)
    pStatus2 = Value
End Property

Public Function addTrueFalse(Key As Long, Status1 As Boolean, Status2 As Boolean)
        If Status1 = True And Status2 = True Then
            If Not pTrueFalse.Exists(True) Then
                pTrueFalse.Add Key:=True, Item:=Key
            Else
                pTrueFalse(True) = pTrueFalse(True) & "," & Key
            End If
        Else
            If Not pTrueFalse.Exists(False) Then
                pTrueFalse.Add Key:=False, Item:=Key
            Else
                pTrueFalse(False) = pTrueFalse(False) & "," & Key
            End If
        End If
End Function

Public Property Get TrueFalse() As Dictionary
   Set TrueFalse = pTrueFalse
End Property


Private Sub Class_Initialize()
    Set pTrueFalse = New Dictionary
End Sub
0 голосов
/ 15 января 2019

Это довольно многословное решение, предполагающее, что ваши данные точно такие же, как вы опубликовали (а также на листе 1), но это работает (я думаю). Вам также нужно будет создать второй лист для выходных данных. Дайте мне знать, если вы не уверены, где разместить этот код / ​​как его запустить.

Sub DoStuff()
    'Initialize the output sheet
    Sheet2.Cells.Clear
    Sheet2.Cells(1, 1) = "Order ID"
    Sheet2.Cells(1, 2) = "ID"
    Sheet2.Cells(1, 3) = "TRUE"
    Sheet2.Cells(1, 4) = "FALSE"
    newRow = 2

    'Loop through the first sheet and remove duplicates
    lastRow = Sheet1.Range("E:E").Cells.SpecialCells(xlCellTypeConstants).Count
    For i = 2 To lastRow
        exists = False
        For j = 2 To newRow
            If Sheet1.Cells(i, 5).Value = Sheet2.Cells(j, 1).Value Then
                exists = True
                Exit For
            End If
        Next
        If exists = False Then
            Sheet2.Cells(newRow, 1) = Sheet1.Cells(i, 5).Value
            Sheet2.Cells(newRow, 2) = Sheet1.Cells(i, 2).Value
            'Populate the true and false columns
            For k = 2 To lastRow
                If Sheet1.Cells(k, 5).Value = Sheet1.Cells(i, 5).Value Then
                    If Sheet1.Cells(k, 3).Value = True And Sheet1.Cells(k, 4).Value = True Then
                        Sheet2.Cells(newRow, 3) = Sheet2.Cells(newRow, 3).Value & Sheet1.Cells(k, 1).Value & ", "
                    Else
                        Sheet2.Cells(newRow, 4) = Sheet2.Cells(newRow, 4).Value & Sheet1.Cells(k, 1).Value & ", "
                    End If
                End If
            Next
            'Remove extra characters, if there are any
            If Sheet2.Cells(newRow, 3).Value <> "" Then
                Sheet2.Cells(newRow, 3).Value = Left(Sheet2.Cells(newRow, 3).Value, Len(Sheet2.Cells(newRow, 3).Value) - 2)
            End If
            If Sheet2.Cells(newRow, 4).Value <> "" Then
                Sheet2.Cells(newRow, 4).Value = Left(Sheet2.Cells(newRow, 4).Value, Len(Sheet2.Cells(newRow, 4).Value) - 2)
            End If
            newRow = newRow + 1
        End If
    Next
End Sub

Результаты с использованием ваших данных, как опубликовано:

enter image description here

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