Removing Helper Columns in Making Combinations - arrays

I have a small tool that generates all the combinations of a set of items using binary patterns. The tool works, but it now requires a "helper" column for each item. (the tool requires no VBA)
I need some help to remove the "helper" columns.
I put the items in the first row starting with B1. In A2, I enter:
=DEC2BIN(ROW()-1,COUNTA($1:$1))
and copy downwards. (this makes the binary patterns)
I fill the "helper" columns (B through E) by putting:
=--MID($A2,COLUMNS($A:A),1)
in B2 and copying both across and downward.
Finally in F2 I enter the array formula:
=TEXTJOIN(",",TRUE,IF($B2:$E2=1,$B$1:$E$1,""))
and copy downwards:
As you can see, the formula is really easy. It looks for the 1's in columns B through E and joins the appropriate words from the first row.
I am trying to replace the $B2:$E2=1 with some kind of MID(A2) function. (this will eliminate the need for columns B, C, D, ...)What I have tried is the array formula:
=TEXTJOIN(",",TRUE,IF(MID(A2,ROW(INDIRECT("1:" & LEN(A2))),1)=1,$B$1:$E$1,""))
But this just yields blanks. Any help will be greatly appreciated!
EDIT#1:
If I use:
=TEXTJOIN(",",TRUE,IF(MID(A2,ROW(INDIRECT("1:" & LEN(A2))),1)="1",$B$1:$E$1,""))
I get a large set of the items, unrelated to the binary pattern.

This array formula (CSE) will eliminate B:E, and is relatively easily expandable to handle more names. It assumes you have the TEXTJOIN function (Office 365)
=TEXTJOIN(",",TRUE,IFERROR(INDEX({"Larry";"Moe";"Curly";"Shep"},N(IF(1,N(AGGREGATE(15,6,1/MID(A2,{1,2,3,4},1)*{1,2,3,4},{1,2,3,4}))))),""))
If permissible, you can replace the array constant containing the names with a vertical list of names.
EDIT: To make the formula more dynamic, enter the list of Names in some column, and NAME it Names, then you can use this formula:
=TEXTJOIN(",",TRUE,IFERROR(INDEX(Names,
N(IF(1,N(AGGREGATE(15,6,1/MID(A2,ROW(INDIRECT(
"1:"&COUNTA(Names))),1)*ROW(INDIRECT("1:"&COUNTA(
Names))),ROW(INDIRECT("1:"&COUNTA(Names)))))))),""))
Of course, you'd then change the A2 formula to:
=IFERROR(DEC2BIN(ROW()-1,COUNTA(Names)),"")
and fill down until you get blanks.
EDIT2: Eliminating Column A, and with a named range named Names:
=TEXTJOIN(",",TRUE,IFERROR(INDEX(Names,N(IF(1,AGGREGATE(
15,6,1/MID(IFERROR(DEC2BIN(ROW()-1,COUNTA(Names)),""),
ROW(INDIRECT("1:"&COUNTA(Names))),1)*ROW(INDIRECT(
"1:"&COUNTA(Names))),ROW(INDIRECT("1:"&COUNTA(Names))))))),""))

This will manually pick up up and return, have to change the frozen values, but its limited to combine only 4 words, the formulas in column A produce a text based result.
=TEXTJOIN(",",TRUE,IF(LEFT(A2,1)="1",$B$1,""),IF(MID(A2,2,1)="1",$C$1,""),IF(MID(A2,3,1)="1",$D$1,""),IF(RIGHT(A2,1)="1",$E$1,""))

Related

Dynamic Spill Formula For Reduce Function Mixed With Split

My sample sheet is probably easier to understand than my writing but here's the issue: I have a sheet that I'm trying to create a spill formula that sums an array of numbers up in each line.
Columns B:D is my existing data that's being evaluated
If values exist in Column D (which is not always the case), split values (defined by , ) and lookup each one's most recent entry (column B) and sum its value from column C with other members in same cell.
I can accomplish this using the Reduce formula shown in my sample data in blue column F, and dragging the formula to the latest entry, however it will not spill down dynamically.
=iferror(REDUCE(0,SPLIT(D2,",",false),lambda(total,value,xlookup(value,B:B,C:C,"",0,-1)+total)),0)
I can get the C values to spill down dynamically (as shown in green columns in sample) as numeric values, but I can't figure out how to sum them.
=Filter(iferror(XLOOKUP(SPLIT(D2:D,", ",false),B:B,C:C,"",0,-1),0),A2:A>0)
I would have expected something like either of these to work, but both generate a #N/A
=Filter(iferror(REDUCE(0,SPLIT(D2:D,", ",false),
lambda(total,value,xlookup(value,B:B,C:C,"",0,-1)+total)),0),A2:A>0)
=Filter(sum(iferror(XLOOKUP(SPLIT(D2:D,", ",false),B:B,C:C,"",0,-1),0)),A2:A>0)
I've also tried these as named functions with only the spilled variables as input, but same result.
I know the reduce function can perform a spilled range, as shown here on Ben Collins' site, however I can't figure out how to get it to do so with my dataset. It's occurred to me that because I'm generating a horizontal array, a verticle array may not be possible?
Any helpful answers will be upvoted if not accepted. Thanks.
Here's one approach:
=byrow(index(map(iferror(split(D2:index(D:D,match(2,1/(D:D<>""))),", ",0,1)),lambda(z,xlookup(z,B:B,C:C,)))),lambda(y,sum(y)))
To have your formula spill down you can use MAP or BYROW:
Your formula:
=iferror(REDUCE(0,SPLIT(D2,", ",false),lambda(total,value,xlookup(value,B:B,C:C,"",0,-1)+total)),0)
With MAP:
=MAP(D2:D7,LAMBDA(ζ,iferror(REDUCE(0,SPLIT(ζ,", ",false),lambda(total,value,xlookup(value,B:B,C:C,"",0,-1)+total)),0)))
Here's another solution using FILTER:
=MAP(D2:INDEX(D:D,MAX(ROW(D:D)*(D:D<>""))),LAMBDA(ζ,IFNA(SUM(FILTER(C:C,COUNTIF(SPLIT(ζ,", ",),B:B))),0)))

Can I make an array out of a range of countif functions?

A truncated version of my data is in the form shown in the screenshot below: three columns of 5 unique names. The names appear in any order and in any position but never repeat in a single row.
My goal is to create an array that contains the number of times Adam appears in each row. I can fill down the formula=countif(A2:C2,$I$2) in a new column, or if I write the array manually for each row, it looks like:
={countif(A2:C2,$I$2);countif(A3:C3,$I$2);countif(A4:C4,$I$2);countif(A5:C5,$I$2);countif(A6:C6,$I$2)}
Where cell I2 contains "Adam". Of course, this is not feasible for large data sets.
I know that arrays are effectively cells turned into ranges, but my main issue is that the cell I'm trying to transform already references a range, and I don't know how to tell the software to apply the countif down each row (i.e. I intuitively would like to do something like countif((A2:C2):(A99:C99),"Adam") but understand that's not how spreadsheets work).
My goal is ultimately to perform some operations on the corresponding array but I think I'm comfortable enough with that once I can get the array formula I'm looking for.
try:
=ARRAYFORMULA(IF(A2:A="",,MMULT(IF(A2:C="Adam", 1, 0), {1;1;1})))

Excel sum values if categories aren't found in a list (better coding method)

I have this code below in the form of an array and I was wondering if there was a cleaner and more dynamic way to code it. (I have removed the $ just to make it easier to read)
SUMPRODUCT(IF((A1:A10 <> D1)*(A1:A10 <> D2),B1:B10))
Column A has a list of names
Column B has a list of values
Column D has a list of names not to include in the calculation
The issue with this formula is that for each new item in column D I have to append another * which would start to make a massive formula.
I tried SUMPRODUCT(IF((A1:A10 <> D1:D2),B1:B10)) but it did not work. Does anyone have any ideas?
P.S. You have to hit CTRL + SHIFT + ENTER to make the cell an array, the formula wont work otherwise.
EDIT: and I can't have D1:DX be the same size as the other ranges as I need the X to be dynamic for my specific scenario
Let's use a helper column to find the "good" rows. In C1 enter:
=IF(ISERROR(MATCH(A1,D:D,0)),1,0)
and copy down. Each "good" name is marked with a 1. In another cell:
=SUMPRODUCT(--(C1:C100)*B1:B100)
For example:
The "helper " column avoids the need for an array formula. You can have as many "bad" names in column D as you like without having to change the formula.
Enter this formula in 'E1':
=SUMPRODUCT($B:$B,ISERROR(MATCH($A:$A,$D:$D,0))*1)

Excel array Formula that copies only cells containing a string

I would prefer to use an excel array formula (but if it can only be done in VBA, so be it) that copies ALL cells from a column array that contains specific text. The picture below shows what I am after and what I have tried. I'm getting close (thanks to similar, but different questions) but can't quite get to where I want. At the moment, I am getting only the first cell instead of all the cells. In my actual application, I am searching through about 20,000 cells and will have a few hundred search terms. I expect most search terms to give me about 8 - 12 cells with that value.
formula I am using:
=INDEX($A$4:$A$10,MATCH(FALSE,ISERROR(SEARCH($C$1,$A$4:$A$10)),0))
Spredsheet Image
To make this work efficiently, I recommend having a separate cell holding the results count (I used cell C2) which has this formula:
=COUNTIF(A:A,"*"&C1&"*")
Then in cell C4 and copied down use this array formula (The -3 is just because the header row is row 3. If the header row was row 1, it would be -1):
=IF(ROW(A1)>$C$2,"",INDEX($A$4:$A$21000,SMALL(IF(ISNUMBER(SEARCH($C$1,$A$4:$A$21000)),ROW($A$4:$A$21000)-3),ROW(C1))))
I tested this with 21000 rows of data in column A with an average of 30 results per search string and the formula is copied down for 60 cells in column C. With that much data, this takes about 1-2 seconds to finish recalculating. Recalculation time can vary widely depending on other factors in your workbook (additional formulas, nested dependencies, use of volatile functions, etc) as well as your hardware.
Alternately, you could just use the built-in Filter functionality, but I hope this helps.
You need to get the ROWS. Put this in C4 and copy down.
=IFERROR(AGGREGATE(15,6, IF(SEARCH($C$1, $A$4:$A$10)>0, ROW($A$4:$A$10)), ROW($C4)-ROW($A$4)+1), "")
Array formula so use ctrl-shift-Enter

turn a matrix into a sorted list google docs/spreadsheets

I've created a large-ish matrix by doing a =pearson( analysis on survey responses in google docs/spreadsheets and would like to convert it into a sorted list.
The matrix has labels (the survey questions) in row 2 and column b. Each intersecting cell has the value. Here's what the formula looks like.
=pearson(FILTER( Pc!$C$2:$AW$999 ; Pc!$C$2:$AW$2= C$2 ),FILTER(Pc!$C$2:$AW$999 ;Pc!$C$2:$AW$2=$B3))
This is what I'd like to get to:
a b c
Question one question 2 correlation
Then sorting by column c is easy.
How can I get all the points out of the matrix/array, along with the labels in this way?
Ideally I'd be able to do this only to points below the diagonal as there of course are dupes above..
Thanks!
I think I found a solution to placing the combination of the headers in a single column.
It involves a series of auxiliary columns, but works.
Let's say we have a single column with all unique headers on column A. I'll assume it's 6 values. So, on cell B1 we paste:
=ArrayFormula(join(";";A1&","&A2:A$6))
And then copy it down to B5. On C1 we join it all and split making a single column:
=transpose(split(join(";";B1:B5);";"))
If needed, we can split the combination in two columns again on D1
=ArrayFormula(split(C1:C15;","))
I don't know why, but the value on E1 does not work correctly, so I just pasted =A2
With these columns you can easily do your nice Pearson-Filter trick again to have it all in a single column. Hope this helps :)
Maybe something like this will help:
=ArrayFormula(transpose(split(CONCATENATE(transpose(C2:AW999)&char(9)), char(9))))
(C2:AW999 is your data range)

Resources