Lambda to count pairs and output array based on criteria

Phantom1

New Member
Joined
Sep 26, 2018
Messages
24
Office Version
  1. 365
  2. 2016
Platform
  1. Windows
I have the following sample data

IDCourse
1000a
1000b
1000c
1001a
1001b
1001d
1002a
1002c
1002d
1003a
1003e
1003f
1004a
1004c
1004f
1005a
1005d
1005f
and need to output with a single formula the following result

abcdefTotal
a62331318
b2211006
c3131019
d3113019
e1000113
f3011139
Total186993954
which is the count of persons for each pair of courses.

I tried the following formula
=LET(
ids, A2:A19,
courses, B2:B19,
uniqueCourses, UNIQUE(courses),
courseRows, INDEX(uniqueCourses, SEQUENCE(ROWS(uniqueCourses), 1)),
courseCols, TRANSPOSE(courseRows),
countMat, MAP(courseRows, courseCols, LAMBDA(cRow,cCol,
SUM( (courses=cRow) * (courses=cCol)))),
countMat)
but got a bunch of #N/A errors.


Any help, suggestions or new formula, will be appreciate.
Thanks in advance
 
Last edited by a moderator:

Excel Facts

Copy formula down without changing references
If you have =SUM(F2:F49) in F50; type Alt+' in F51 to copy =SUM(F2:F49) to F51, leaving the formula in edit mode. Change SUM to COUNT.
When using MAP with more than one array, they need to be the same size & shape.
How about
Fluff.xlsm
ABCDEFGHIJ
1IDCourse
21000a abcdef
31000ba623313
41000cb221100
51001ac313101
61001bd311301
71001de100011
81002af301113
91002c
101002d
111003a
121003e
131003f
141004a
151004c
161004f
171005a
181005d
191005f
Sheet6
Cell Formulas
RangeFormula
D2:J8D2=LET(Data,FILTER(A2:B100,A2:A100<>""),Id,INDEX(Data,,1),Course,INDEX(Data,,2),u,UNIQUE(Course),REDUCE(HSTACK("",TOROW(u)),u,LAMBDA(x,y,VSTACK(x,HSTACK(y,DROP(REDUCE("",u,LAMBDA(a,b,LET(f,FILTER(Id,(Course=y)+(Course=b)),HSTACK(a,IF(b=y,ROWS(f),(ROWS(f)-ROWS(UNIQUE(f,,1)))/2))))),,1))))))
Dynamic array formulas.
 
Upvote 0
Another option (Fluff's is definitely better though):

Excel Formula:
=LET(
ID,A2:A19,
courses,B2:B19,
u_c,UNIQUE(courses),
u_i,UNIQUE(ID),
m,u_c&" | "&TRANSPOSE(u_c),
n,TOCOL(DROP(REDUCE("",u_i,LAMBDA(x,y,VSTACK(x,FILTER(courses,ID=y)&" | "&TRANSPOSE(FILTER(courses,ID=y))))),1)),
count,WRAPROWS(MAP(TOCOL(m),LAMBDA(x,SUM(--(n=x)))),COLUMNS(m)),
t_1,VSTACK(count,BYCOL(count,SUM)),
t_2,HSTACK(t_1,BYROW(t_1,SUM)),
l,HSTACK(VSTACK(u_c,"Total"),t_2),
VSTACK(HSTACK("",TRANSPOSE(u_c),"Total"),l))
 
Upvote 0
Another way

24 10 09.xlsm
ABCDEFGHIJ
1IDCourse
21000a abcdef
31000ba623313
41000cb221100
51001ac313101
61001bd311301
71001de100011
81002af301113
91002c
101002d
111003a
121003e
131003f
141004a
151004c
161004f
171005a
181005d
191005f
Courses
Cell Formulas
RangeFormula
D2:J8D2=LET(b,B2:B19,u,UNIQUE(b),w,ROWS(u)+1,MAKEARRAY(w,w,LAMBDA(r,c,LET(x,INDEX(u,r-1),y,INDEX(u,c-1),f,FILTER(A2:A19,(b=x)+(b=y)),IF(r=1,IF(c=1,"",y),IF(c=1,x,IF(r=c,COUNTIF(b,x),COUNT(UNIQUE(FILTER(f,XMATCH(f,f)<XMATCH(f,f,,-1)))))))))))
Dynamic array formulas.
 
Upvote 0
These are all very interesting, but I see only the solution offered by @hagia_sofia includes the totals, as per the original post. In any case, here's my attempt at a solution (without including the totals, though :) ) ....

phantom.xlsm
ABCDEFGHIJKL
1IDCourse
21000a abcdef
31000ba623313
41000cb221100
51001ac313101
61001bd311301
71001de100011
81002af301113
91002c
101002d
111003a
121003e
131003f
141004a
151004c
161004f
171005a
181005d
191005f
20
21
22
Sheet1
Cell Formulas
RangeFormula
D2:J8D2=LET(rngID,A2:A19,rngCourse,B2:B19,uniqueCourses,SORT(UNIQUE(rngCourse)),array,MAKEARRAY(COUNTA(uniqueCourses),COUNTA(uniqueCourses),LAMBDA(x,y,SUM(IF(ISNUMBER(MATCH(IF(rngCourse=INDEX(uniqueCourses,x),rngID,"@"),IF(rngCourse=INDEX(uniqueCourses,y),rngID,"#"),0)),1)))),table,HSTACK(uniqueCourses,array),table2,VSTACK(HSTACK("",TOROW(uniqueCourses)),table),table2)
Dynamic array formulas.
 
Upvote 0
but I see only the solution offered by @hagia_sofia includes the totals, as per the original post.
Good catch :)
:eek: Must have had these on :cool:

24 10 09.xlsm
ABCDEFGHIJK
1IDCourse
21000a abcdefTotal
31000ba62331318
41000cb2211006
51001ac3131019
61001bd3113019
71001de1000113
81002af3011139
91002cTotal186993954
101002d
111003a
121003e
131003f
141004a
151004c
161004f
171005a
181005d
191005f
Courses (2)
Cell Formulas
RangeFormula
D2:K9D2=LET(b,B2:B19,u,UNIQUE(b),w,ROWS(u)+1,t,"Total",m,MAKEARRAY(w,w,LAMBDA(r,c,LET(x,INDEX(u,r-1),y,INDEX(u,c-1),f,FILTER(A2:A19,(b=x)+(b=y)), IF(r=1,IF(c=1,"",y),IF(c=1,x,IF(r=c,COUNTIF(b,x),COUNT(UNIQUE(FILTER(f,XMATCH(f,f)<XMATCH(f,f,,-1)))))))))),MAKEARRAY(w+1,w+1, LAMBDA(g,h,IF(g=w+1,IF(h=1,t,IF(h=w+1,SUM(m),SUM(INDEX(m,0,h)))),IF(h=w+1,IF(g=1,t,SUM(INDEX(m,g,0))),INDEX(m,g,h))))))
Dynamic array formulas.
 
Upvote 0
Just for fun, here's one more option to add to the mix:

Excel Formula:
=LET(
    id, A2:A1000,
    cr, B2:B1000,
    u, UNIQUE(TOROW(cr,1),1),
    n, COLUMNS(u),
    k, COUNTIFS(id,UNIQUE(TOCOL(id,1)),cr,u),
    m, MAKEARRAY(n,n,LAMBDA(i,j,SUM(CHOOSECOLS(k,i)*CHOOSECOLS(k,j)))),
    t, MMULT(m,EXPAND(1,n,,1)),
    VSTACK(HSTACK("Course",u,"Total"),HSTACK(TOCOL(u),m,t),HSTACK("Total",TOROW(t),SUM(t)))
)

It's also entirely possible to use MAP by broadcasting the unique course list both down and across in two separate arrays. As a demonstration, consider Fluff's solution:

Excel Formula:
=LET(
    data, FILTER(A2:B1000,A2:A1000<>""),
    id, INDEX(data,,1),
    cr, INDEX(data,,2),
    i, UNIQUE(cr),
    j, TOROW(i),
    m, MAP(IF({1},i,j),IF({1},j,i),LAMBDA(a,b,LET(f,FILTER(id,(cr=a)+(cr=b)),IF(a=b,ROWS(f),(ROWS(f)-ROWS(UNIQUE(f,,1)))/2)))),
    t, MMULT(m,IF({1},1,i)),
    VSTACK(HSTACK("Course",j,"Total"),HSTACK(i,m,t),HSTACK("Total",TOROW(t),SUM(t)))
)

Cheers!
 
Upvote 0
Thank you all very much.
Quick responses and accurately.
All of your answers worked perfectly.
Still can decide which solution is more elegant and straight forward though. All of them are definitely above my skills.😂
 
Upvote 0
You are welcome. Glad we could help. :)
(Good luck choosing but the first one in post 7 looks pretty good to me)
 
Upvote 0
Because i have my data in a table that has more than 100 000 rows and 30 columns the functions above take a lot time to calculate. Is there any workthrough?
Also can we add an optional argument in lambda to filter by criteria on values of ids or other columns before counting? This will be very handy as it minimizes the data to process.
Thanks again
 
Upvote 0

Forum statistics

Threads
1,224,823
Messages
6,181,176
Members
453,021
Latest member
Justyna P

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top