Home » Match Payments!

Match Payments!

Solving Match Payments challenge by Power Query, Power BI, Excel, Python and R

The customer receipt costs and their payments are provided in Question Tables 1 and 2. We want to match the payments with the receipts based on the date, as shown in the result table. Receipts that are not paid will be marked as “NP” (Not Paid). For example, Payment ID P1 is used to pay for receipts C1 to C3.

📌 Challenge Details and Links
Challenge Number: 60
Challenge Difficulty: ⭐⭐⭐⭐
📥Download Sample File
📥Link to the solutions on LinkedIn

Solving the challenge of Match Payments! with Power Query

Power Query solution 1 for Match Payments!, proposed by Zoran Milokanović:
let
  Source = each Excel.CurrentWorkbook(){[Name = _]}[Content], 
  T1 = Source("Table1"), 
  T2 = Source("Table2"), 
  S = Table.FromRows(
    List.TransformMany(
      Table.ToRows(T1), 
      each 
        let
          r = List.Sum(List.FirstN(T1[Cost], List.PositionOf(T1[ID], _{0}))) ?? 0, 
          p = T2[Payment]
        in
          {
            List.Accumulate(
              List.Positions(p), 
              {}, 
              (s, c) =>
                s
                  & {
                    let
                      i  = List.Sum(s) ?? 0, 
                      pp = List.Sum(List.FirstN(p, c)) ?? 0
                    in
                      {
                        {null, List.Min({pp - r + p{c} - i, _{2} - i})}{
                          Number.From(pp - r + p{c} - i > 0)
                        }, 
                        null
                      }{Number.From(_{2} = i)}
                  }
            )
          }, 
      (i, _) =>
        {i{0}} & {List.Repeat({"NP"}, List.Count(_)), _}{Number.From(List.NonNullCount(_) > 0)}
    ), 
    {" "} & T2[ID]
  )
in
  S
Power Query solution 2 for Match Payments!, proposed by Rafael González B.:
let
 Rec = Recipts, Pay = Payments, R = "Running",
 Fx_RunTotal = (L as list, T as table) => 
 let 
 aa = List.Generate(
 () => [i = 1, Acum = L{0} ],
 each [i] <= List.Count(L),
 each [
 i = [i] + 1,
 Acum = [Acum] + L{[i]}],
 each [Acum]),
 bb = Table.ToColumns(T),
 cc = Table.FromColumns(bb & {aa}, Table.ColumnNames(T) & {R})
 in 
 cc,
 Rec2 = let 
 a = Table.AddColumn(Rec, "Unit", each List.Repeat({1}, [Cost])),
 b = Table.ExpandListColumn(a, "Unit")
 in 
 b,
 
Power Query solution 3 for Match Payments!, proposed by Aditya Kumar Darak 🇮🇳:
let
  Receipts = Excel.CurrentWorkbook(){[Name = "receipts"]}[Content], 
  Payments = Excel.CurrentWorkbook(){[Name = "payments"]}[Content], 
  Generate = List.Generate(
    () => [n1 = - 1, n2 = - 1, rr = 0, rp = 0], 
    each [n1] < Table.RowCount(Receipts) and [n2] < Table.RowCount(Payments), 
    each [
      n1 = [n1] + Number.From(t1), 
      n2 = [n2] + Number.From(t2), 
      r  = Receipts{n1}, 
      ri = r[ID], 
      rc = r[Cost], 
      p  = Payments{n2}, 
      pi = p[ID], 
      pp = p[Payment], 
      t1 = [rr] = 0, 
      t2 = [rp] = 0, 
      AU = List.Min({if t2 then pp else [rp], if t1 then rc else [rr]}), 
      rr = if t1 then rc - AU else [rr] - AU, 
      rp = if t2 then pp - AU else [rp] - AU
    ], 
    each [ID = [ri], P = [pi], A = [AU]]
  ), 
  Table = Table.FromRecords(List.Skip(Generate)), 
  Pivot = Table.Pivot(Table, Payments[ID], "P", "A", each _{0}? ?? ""), 
  Join = Table.AddJoinColumn(Receipts[[ID]], {"ID"}, Pivot, {"ID"}, "J"), 
  Expand = Table.ExpandTableColumn(Join, "J", Payments[ID]), 
  Replace = Table.ReplaceValue(Expand, null, "NP", (x, y, z) => x ?? z, Payments[ID]), 
  Return = Table.Sort(Replace, each List.PositionOf(Receipts[ID], [ID]))
in
  Return
Power Query solution 4 for Match Payments!, proposed by Alejandro Simón 🇵🇦 🇪🇸:
let
 Source = List.Combine(Table.AddColumn(Excel.CurrentWorkbook(){[Name="Table1"]}[Content], "A", each List.Repeat({[ID]}, [Cost]))[A]),
 Tbl2 = List.Combine(Table.AddColumn(Excel.CurrentWorkbook(){[Name="Table2"]}[Content], "A", each List.Repeat({[ID]}, [Payment]))[A]),
 Tbl = Table.FromColumns({Source, Tbl2}),
 Group = Table.Group(Tbl, {"Column1"}, {{"A", each 
let
a = _,
b = Table.Group(a, "Column2", {{"B", each List.Count([Column1])}}),
c = Table.SelectRows(b, each [Column2]<>null),
d = Table.PromoteHeaders(Table.Transpose(c)),
e = if Table.IsEmpty(d) then Table.FromRows({List.Repeat({"NP"}, 
 List.Count(List.Distinct(Tbl2)))}, List.Distinct(Tbl2)) else d
in e}}),
 Sol = Table.ExpandTableColumn(Group, "A", List.Distinct(Tbl2))
in
 Sol

Solving the challenge of Match Payments! with Excel

Excel solution 1 for Match Payments!, proposed by Bo Rydobon 🇹🇭:
=LET(d,
    DROP(
        REDUCE(
            B3:B14,
            H3:H7,
            LAMBDA(
                b,
                w,
                HSTACK(
                    b,
                    DROP(
                        
                        REDUCE(
                            w,
                            D3:D14-BYROW(
                                b,
                                SUM
                            ),
                            LAMBDA(
                                a,
                                v,
                                VSTACK(
                                    a,
                                    MIN(
                                        @a*2-SUM(
                                            a
                                        ),
                                        v
                                    )
                                )
                            )
                        ),
                        1
                    )
                )
            )
        ),
        ,
        0
    ),VSTACK(TOROW(
    F2:F7
),
    IF(BYROW(
        d,
        SUM
    )+(d>""),
    d,
    "NP")))
Excel solution 2 for Match Payments!, proposed by محمد حلمي:
=LET(
    s,
    SEQUENCE(
        5
    ),    i,
    CHOOSECOLS(        REDUCE(
            D3:D14,
            H3:H7,
            LAMBDA(
                a,
                w,
                LET(
                    
                    v,
                    TAKE(
                        a,
                        ,
                        -1
                    ),
                    
                    e,
                    DROP(
                        SCAN(
                            ,
                            VSTACK(
                                w,
                                v
                            ),
                            LAMBDA(
                                a,
                                v,
                                a-v
                            )
                        ),
                        -1
                    ),
                    
                    HSTACK(
                        a,
                        IFS(
                            e>v,
                            v,
                            e>0,
                            e,
                            1,
                            
                        ),
                        
                        IFS(
                            e>v,
                            0,
                            e<0,
                            v,
                            1,
                            v-e
                        )
                    )
                )
            )
        ),
        s*2
    ),    IF(
        MMULT(
            i,
            s^0
        ),
        i,
        "NP"
    )
)
Excel solution 3 for Match Payments!, proposed by Julian Poeltl:
=LET(T,
    B3:D14,
    TT,
    F3:H7,
    RT,
    SCAN(
        ,
        TAKE(
            T,
            ,
            -1
        ),
        LAMBDA(
            A,
            B,
            A+B
        )
    ),
    RTT,
    SCAN(
        ,
        TAKE(
            TT,
            ,
            -1
        ),
        LAMBDA(
            A,
            B,
            A+B
        )
    ),
    RC,
    ROWS(
        T
    ),
    CP,
    ROWS(
        TT
    ),
    FP,
    XMATCH(
        RT,
        RTT,
        1
    ),
    Gap,
    --(FP=VSTACK(
        1,
        FP
    )),
    FullP,
    IF(
        Gap,
        TAKE(
            T,
            ,
            -1
        ),
        ""
    ),
    SR,
    SEQUENCE(
        RC
    ),
    CPS,
    SEQUENCE(
        ,
        CP
    ),
    C,
    ABS(
        IF(
            RT>0,
            INDEX(
                RTT,
                FP-1
            )
        )-RT
    ),
    CC,
    IF(
        FullP="",
        C,
        FullP
    ),
    Field1,
    XLOOKUP(
        SR&CPS,
        SR&FP,
        DROP(
            CC,
            -1
        ),
        0
    ),
    BRS,
    TRANSPOSE(
        TAKE(
            TT,
            ,
            -1
        )
    )-BYCOL(
        Field1,
        LAMBDA(
            A,
            SUM(
                A
            )
        )
    ),
    CCC,
    --(Field1>0)*SR,
    BCM,
    BYCOL(
        CCC,
        LAMBDA(
            A,
            MAX(
                A
            )
        )
    ),
    CCCC,
    IF(
        BCM>0,
        BCM+1
    ),
    SC,
    SCAN(
        ,
        CCCC,
        LAMBDA(
            A,
            B,
            IF(
                B=FALSE,
                A,
                B
            )
        )
    ),
    Field2,
    IF(
        SR*SEQUENCE(
            ,
            ROWS(
        TT
    ),
            ,
            0
        )=SC,
        BRS,
        0
    ),
    R,
    Field1+Field2,
    M,
    MIN(
        IFERROR(
            DROP(
            CC,
            -1
        ),
            SR
        )
    )-1,
    RR,
    VSTACK(
        HSTACK(
            "",
            TRANSPOSE(
                TAKE(
                    TT,
                    ,
                    1
                )
            )
        ),
        HSTACK(
            TAKE(
                T,
                ,
                1
            ),
            EXPAND(
                TAKE(
                    R,
                    M
                ),
                RC,
                ,
                "NP"
            )
        )
    ),
    IF(
        RR<>0,
        RR,
        ""
    ))
Excel solution 4 for Match Payments!, proposed by John Jairo Vergara Domínguez:
=LET(
    c,
    D3:D14,
    h,
    HSTACK,
    v,
    VSTACK,
    n,
    DROP(
        REDUCE(
            0*c,
            H3:H7,
            LAMBDA(
                b,
                w,
                h(
                    b,
                    DROP(
                        REDUCE(
                            0,
                            c-BYROW(
                                b,
                                SUM
                            ),
                            LAMBDA(
                                a,
                                z,
                                v(
                                    a,
                                    MIN(
                                        w-SUM(
                                            a
                                        ),
                                        z
                                    )
                                )
                            )
                        ),
                        1
                    )
                )
            )
        ),
        ,
        1
    ),
    v(
        h(
            "",
            TOROW(
                F3:F7
            )
        ),
        h(
            B3:B14,
            IF(
                BYROW(
                    n,
                    SUM
                ),
                n,
                "NP"
            )
        )
    )
)
Excel solution 5 for Match Payments!, proposed by John Jairo Vergara Domínguez:
=LET(f,
    VSTACK,
    n,
    REDUCE(
        B3:B14,
        -H3:H7,
        LAMBDA(
            i,
            x,
            HSTACK(
                i,
                DROP(
                    REDUCE(
                        x,
                        BYROW(
                            i,
                            SUM
                        )-D3:D14,
                        LAMBDA(
                            a,
                            v,
                            f(
                                a,
                                -MAX(
                                    v,
                                    SUM(
                                        a
                                    )
                                )
                            )
                        )
                    ),
                    1
                )
            )
        )
    ),
    f(TOROW(
        F2:F7
    ),
    IF(BYROW(
        n,
        SUM
    )+(n>0),
    n,
    "NP")))
Excel solution 6 for Match Payments!, proposed by Hussein SATOUR:
=LET(
    d,
    ROW(
        1:12
    ),
    e,
    J3:J7,
    f,
    LAMBDA(
        x,
        y,
        TEXTSPLIT(
            CONCAT(
                REPT(
                    x&"|",
                    y
                )
            ),
            ,
            "|",
            1
        )
    ),
    a,
    --f(
        d,
        D3:D14
    ),
    b,
    f(
        H3:H7,
        e
    ),
    c,
    --f(
        1,
        e
    ),
    IFNA(
        HSTACK(
            VSTACK(
                "",
                "C"&d
            ),
             DROP(
                 PIVOTBY(
                     TAKE(
                         a,
                         SUM(
                             e
                         )
                     ),
                     b,
                     c,
                     SUM,
                     ,
                     0,
                     ,
                     0
                 ),
                 ,
                 1
             )
        ),
        "NP"
    )
)
Excel solution 7 for Match Payments!, proposed by LUIS FLORENTINO COUTO CORTEGOSO:
=LET(c,
    D3:D14,
    p,
    H3:H7, rc,
    ROWS(
        c
    ),
    rp,
    ROWS(
        p
    ), cz,
    SEQUENCE(
        rc,
        ,
        0,
        0
    ), pz,
    SEQUENCE(
        ,
        rp,
        0,
        0
    ), cx,
    MAKEARRAY(
        rc,
        rp,
        LAMBDA(
            x,
            y,
            INDEX(
                c,
                x
            )
        )
    ), cs,
    MAKEARRAY(
        rc,
        rp,
        LAMBDA(
            x,
            y,
            SUM(
                TAKE(
                c,
                x
            )
            )
        )
    ), ps,
    MAKEARRAY(
        rc,
        rp,
        LAMBDA(
            x,
            y,
            SUM(
                TAKE(
                    p,
                    y
                )
            )
        )
    ), csd,
    VSTACK(
        pz,
        DROP(
            cs,
            -1
        )
    ), a,
    IF(csd0,
    cx,
    ps-csd),
    0), b,
    HSTACK(
        DROP(
            a,
            ,
            1
        ),
        cz
    ), r,
    HSTACK(
        TAKE(
            a,
            ,
            1
        ),
        DROP(
            b-a,
            ,
            -1
        )
    ), IF(
     BYROW(
         r,
         SUM
     )=0,
     "NP",
     IF(
         r=0,
         "",
         r
     )
 )
)

Solving the challenge of Match Payments! with R

R solution 1 for Match Payments!, proposed by Konrad Gryczan, PhD:
library(tidyverse)
library(readxl)

input1 = read_excel("files/CH-060 Match payments.xlsx", range = "B2:D14")
input2 = read_excel("files/CH-060 Match payments.xlsx", range = "F2:H7")
test  = read_excel("files/CH-060 Match payments.xlsx", range = "K2:P14")


rec = input1 %>%
 mutate(ID = factor(ID, levels = paste0("C", 1:12), ordered = TRUE)) %>%
 uncount(Cost, .remove = FALSE) %>%
 mutate(Cost = 1, rn = row_number())

pay = input2 %>%
 mutate(ID = factor(ID, levels = paste0("P", 1:5), ordered = TRUE)) %>%
 uncount(Payment, .remove = FALSE) %>%
 mutate(Payment = 1, rn = row_number())

all = full_join(rec, pay, by = "rn") %>%
 summarise(Value = sum(Payment), .by = c("ID.x", "ID.y")) %>%
 pivot_wider(names_from = "ID.y", values_from = "Value") %>%
 select(-"NA") %>%
 mutate(across(everything(), as.character))
R solution 2 for Match Payments!, proposed by Anil Kumar Goyal:
library(readxl)
library(tidyverse)

rec <- read_excel("OM Challanges/CH-060 Match payments.xlsx", 
 range = "B2:D14")
pymt <- read_excel("OM Challanges/CH-060 Match payments.xlsx", 
 range = "F2:H7") 

rec %>% 
 mutate(cum_r = cumsum(Cost),
 cum_r_prev = lag(cum_r, default = 0)) %>% 
 left_join(
 pymt %>% 
 mutate(cum_p = cumsum(Payment),
 cum_p_prev = lag(cum_p, default = 0)),
 by = join_by(overlaps(cum_r_prev, cum_r, cum_p_prev, cum_p, bounds = "()"))
 ) %>% 
 mutate(ID.x, ID.y,
 matching = pmin(cum_r, cum_p),
 matching = c(first(matching), diff(matching)),
 .keep = "none") %>% 
 fill(ID.y) %>% 
 pivot_wider(id_cols = ID.x, names_from = ID.y, values_from = matching, 
 values_fill = 0)

Leave a Reply