I have one list starting from B1 (=UNIQUE(A1:A8)), and another list starting from D1 (=UNIQUE(C1:C8)). Thus =B1# and =D1# in other cells both spill.
Now, I would like to know if we could find one formula to combine List B1# and List D1# (extract only unique values) by dynamic array functions, LAMBDA, LET, etc.
I don't want to move the position of the two lists. Does anyone have any good idea?
I may not be following what you want the shape to be, but here are two shapes:
Side-by-Side
=CHOOSE({1,2},B1#,D1#)
If you want it to take the original A and C columns as input and do all the work, then:
=CHOOSE({1,2},UNIQUE(FILTER(A:A,NOT(ISBLANK(A:A)))),UNIQUE(FILTER(C:C,NOT(ISBLANK(C:C)))))
or a LET version of the same which does not require retyping the inputs:
=LET( Ltrs, A:A,
Nmbrs, C:C,
CHOOSE( {1,2},
UNIQUE(FILTER(Ltrs,NOT(ISBLANK(Ltrs)))),
UNIQUE(FILTER(Nmbrs,NOT(ISBLANK(Nmbrs)))) ) )
End-on-End
=LET( uLtrs, B1#,
uNmbrs, D1#,
ltrCt, ROWS(uLtrs),
idx, SEQUENCE( ltrCt + ROWS(uNmbrs) ),
IF( idx <= ltrCt, uLtrs, INDEX( uNmbrs, idx-ltrCt ) ) )
Similar as above, if you want it to take the original A and C columns as input and do all the work, then:
=LET( Ltrs, A:A,
Nmbrs, C:C,
uLtrs, UNIQUE(FILTER(Ltrs,NOT(ISBLANK(Ltrs)))),
uNmbrs, UNIQUE(FILTER(Nmbrs,NOT(ISBLANK(Nmbrs)))),
ltrCt, ROWS(uLtrs),
idx, SEQUENCE( ltrCt + ROWS(uNmbrs) ),
IF( idx <= ltrCt, uLtrs, INDEX( uNmbrs, idx-ltrCt ) ) )
Both spill the results.
Place the following code into cell F2 and drag formula downwards to F14. This will give you a unique list of both Column A and Column D
=IF(IFERROR(IF(INDEX($A$1:$A$99999,MATCH(0,COUNTIF($F$1:F1,$A$1:$A$99999),0))=0,NA(),INDEX($A$1:$A$99999,MATCH(0,COUNTIF($F$1:F1,$A$1:$A$99999),0))),INDEX($C$1:$C$99999,MATCH(0,COUNTIF($F$1:F1,$C$1:$C$99999),0)))=0,NA(),IFERROR(IF(INDEX($A$1:$A$99999,MATCH(0,COUNTIF($F$1:F1,$A$1:$A$99999),0))=0,NA(),INDEX($A$1:$A$99999,MATCH(0,COUNTIF($F$1:F1,$A$1:$A$99999),0))),INDEX($C$1:$C$99999,MATCH(0,COUNTIF($F$1:F1,$C$1:$C$99999),0))))
Let me know if you need it to behave differently.
Related
In column A, starting with A1, I have a set of database column names which are Pascale case and without spaces. I'd like to use an Excel formula in column B to insert spaces before each Capital letter or number. Ideally any consecutive capital letters or numbers would remain together. I've done this in the past with C#, but on this project, I can't even use VBA macros. Example output:
Can this, or something close, be achieved using only formulas?
This is pretty hard, but with ms365 doable with the give sample data:
Formula in B1:
=MAP(A1:A10,LAMBDA(v,TRIM(REDUCE(v,SEQUENCE(LEN(v),,LEN(v),-1),LAMBDA(a,b,LET(x,MAKEARRAY(26,3,LAMBDA(r,c,CHOOSE(c,CHAR(r+64),CHAR(r+96),r-0))),y,MID(a,b,1),z,MID(a,b+1,1),r,BYCOL(x,LAMBDA(c,SUM(EXACT(c,y)+EXACT(c,z)))),IF(MAX(r)=1,LEFT(a,b-1)&IF((CONCAT(r)="110")*(EXACT(UPPER(y),y))," "&y,y&" ")&RIGHT(a,LEN(a)-b),a)))))))
Maybe others have shorter solutions...
Just for fun, this uses a single Reduce but I have defined some auxiliary functions. I put them in a module called 'is' in the Advanced Formula Environment so their full names are Is.Upper, Is.Lower and Is.Digit:
Upper=lambda(c,if(c="",false,and(code(c)>64,code(c)<91)));
Digit=lambda(c,if(c="",false,and(code(c)>47,code(c)<58)));
Lower=lambda(c,if(c="",false,and(code(c)>96,code(c<123))))
=REDUCE(LEFT(A1,1),SEQUENCE(1,LEN(A1)-1,2),LAMBDA(a,c,a&IF(OR(AND(is.Digit(MID(A1,c,1)),NOT(is.Digit(MID(A1,c-1,1)))),AND(is.Upper(MID(A1,c,1)),OR(NOT(is.Upper(MID(A1,c-1,1))),is.Lower(MID(A1,c+1,1)))))," ","")&MID(A1,c,1)))
This is how the main formula looks in the Advanced Formula Environment:
=REDUCE(
LEFT(A2, 1),
SEQUENCE(1, LEN(A2) - 1, 2),
LAMBDA(a, c,
a &
IF(
OR(
AND(
is.Digit(MID(A2, c, 1)),
NOT(is.Digit(MID(A2, c - 1, 1)))
),
AND(
is.Upper(MID(A2, c, 1)),
OR(
NOT(is.Upper(MID(A2, c - 1, 1))),
is.Lower(MID(A2, c + 1, 1))
)
)
),
" ",
""
) & MID(A2, c, 1)
)
)
Note - assumes string length>1.
How to split the data from one cell to 8 rows in excel
For example:
There is given long data in one cell: 65178492194051241284...
The sorted values should look like:
65:17:84:92
40:51:24:12
Excel offers multiple options to help you build your own formula
LEFT is used to extract characters from the LEFT of the string (also MID might be useful in your case)
https://www.excel-easy.com/examples/substring.html
Combining LEFT/MID with CONCATENATE you should be able to produce the expected output
https://edu.gcfglobal.org/en/excelformulas/using-concatenate-to-combine-names/1/
Something similar to
=CONCATENATE(LEFT(A1,2),':',MID(A1,2,2),':', MID(A1,4,2),.... )
You have Excel365 then could try-
=TEXTJOIN(":",TRUE,MID(INDEX(MID($A$1,SEQUENCE(INT(LEN($A$1)/8)+1,,1,8),8),ROW(1:1)),{1,3,5,7},2))
This will only work in Excel 365:
=MID(TEXTJOIN(":",TRUE,MID(A1,SEQUENCE(1,LEN(A1)/2,1,2),2)),SEQUENCE(LEN(A1)/8,, 0)*12+1,11)
Or if you want a more readable (and slightly faster running) version:
=LET( t,A1,
L, LEN( t ),
S, TEXTJOIN( ":", TRUE, MID( t, SEQUENCE( 1, L / 2, 1, 2 ), 2) ),
MID( S, SEQUENCE( L/8,, 0 )*12 + 1, 11 ) )
With Microsoft Excel 365 you can use:
Formula in C1:
=TEXT(MID(A1,SEQUENCE(LEN(A1)/8,,,8),8),"00\:00\:00\:00")
If you haven't always have an exact multiple of 8 characters you should nest FLOOR():
=TEXT(MID(A1,SEQUENCE(FLOOR(LEN(A1)/8,1),,,8),8),"00\:00\:00\:00")
I have been trying to make this work in cell I1:
=IF(B18="","",IF(AND(OR(C16=7,C16="J",C16=8),B18< 300,D16< DATE(2021,5,15),300,IF(B18< 350),350,B18),(IF(AND(OR(C16=4,C16="T"),B18< 500),500,B18))))
Where:
if C16 is 7 or J or 8
and
the date in D16< DATE(2021,5,15)
and
B18<300
Result in I1=300 otherwise B18 (in case B18 is over 300).
Otherwise if D16> DATE(2021,5,15) and B18<350 I1=350.
If B18>350, I1=B18
Sorry...it looks messy!
R
It seems like your formula and code don't align with each other.
But however, with the explanation you have provided, I could only write the following formula. Hope it works for you.
=IF( B18="" , "" , IF( AND( OR(C16=7,C16="J",C16=8), D16<DATE(2021,5,15) ) , IF(B18<300, 300, B18), IF( D16>DATE(2021,5,15) , IF(B18<350, 350, B18) ) ) )
I think I solved it like this:
=IF(B18="","",IF(AND(OR(C16=4,C16="T"),B18<500),500,IF(AND(OR(C16=7,C16="J",C16=8),B18<300,D16<DATE(2021,5,15)),300,IF(B18<350,350,B18))))
I have a spreadsheet that is using the SUMIF function. It works very well to summarize single values from another column but I want to be able to potentially multiply a single entries value before summing it.
I'm unable to attach photos so I'll try to describe. My spreadsheet has this equation on it:
=SUMIF(L25:L31,"x",$K$25:$K$31)
Then if I put an 'x' on a row in column 'L' it will include the value from column 'K' in the summation. I want to be able to use 'x2', 'x3', 'x4', etc. and multiply the value before the summation. Is that possible with Excel?
Multiplication is distributive; the product of the sum is the same as the sum of the products. So you can move the multiplier to the outside of the equation if I am understanding your question correctly. Where "y" is the multiplier and "x" is the criteria you are looking up, the below should work:
=y*SUMIF(L25:L31,"x",$K$25:$K$31)
If the multiple is a variable, then I would suggest adding helper columns, and simply change the sum range on the SUMIF formula.
Note that the SUMPRODUCT suggested does not take into account the conditional nature of the sum that I assume you are looking for (otherwise why would you use SUMIF instead of SUM?)
This should do the trick:
=SUMPRODUCT(IFERROR($K$25:$K$31*IF($L$25:$L$31="x",1,MID($L$25:$L$31,2,255)),0))
But must the "x" be there? If you have the flexibility to switch to 1, 2, 3 instead of x, x2 and x3, that would open up to simplify the formula to this
=SUMPRODUCT($K$25:$K$31*$L$25:$L$31)
The latter should be more efficient as well, in case your actual data is large.
If I've not misunderstood, this would produce the result of applying a variable multiplier to the qualified data points and then sum it up:
=SUM( (L25:L30="x") * K25:K30 * {1;2;3;4;5;6} )
The 1;2;3... column array is arbitrary - I just invented it for example. If it really is an incremental sequence, then you can produce the same this way and gain the advantage that it is easier to extend (without typing lots of numbers):
=SUM( (L25:L30="x") * K25:K30 * SEQUENCE( ROWS(L25:L30) ) )
If this is the solution and you really want to streamline it, then make it a little cleaner with LET:
=LET( sumRange, K25:K30,
criteriaRange, L25:L30,
criteria, "x",
size, MIN( ROWS( criteriaRange), ROWS( sumRange ) ),
SUM( (criteriaRange = criteria ) * sumRange * SEQUENCE( size ) ) )
If the multipliers are not an incremental sequence, then a third variable could be introduced to replace SEQUENCE( size ) that would contain the multiplier array.
In Excel 2010, I have set up a two dimensional table that is filled with percent errors. These percentages are calculated based on a user input, so the values change depending on what value the user asks for.
What I would like to do is be able to find the location of the cell in the table that is closest to zero, and return the row and column of that data point for further calculations. Is there a way to do this without using a macro?
Thanks in advance for any help.
EDIT: The percent errors are non-negative, and may appear more than once in the table.
That would be too unreliable for cells with the same absolute value closest to 0 (for example -1 and 1).
This array formula will get the absolute value closest to 0:
{ = MIN( ABS( Table1 ) ) }
Where Table1 is the name of the table or range. If the table has values -1 and 1, then it will return 1.
Then those array formulas to get the max row and max column of the values closest to 0
{ = MAX( ROW(Table1) * (ABS(Table1) = MIN(ABS(Table1))) ) }
{ = MAX( COLUMN(Table1) * (ABS(Table1) = MIN(ABS(Table1))) ) }
Update
This array formula should work for your mirrored data:
{ = ADDRESS( MIN( IF( ABS(Table1) = MIN(ABS(Table1)), ROW(Table1) ) ),
MAX( IF( ABS(Table1) = MIN(ABS(Table1)), COLUMN(Table1) ) ) ) }
You can remove the ABS parts if there are no negative values:
{ = ADDRESS( MIN( IF(Table1 = MIN(Table1), ROW(Table1) ) ),
MAX( IF(Table1 = MIN(Table1), COLUMN(Table1) ) ) ) }
The trick is that Min and Max ignore logical values, so I omitted the third parameter of the If
Update 2
This array formula is a bit simplified version of #JohnBustos 's answer (I am still not sure why he uses SMALL instead of MIN):
{ = MIN( IF(Table1=MIN(Table1), ROW(Table1)*1000 +COLUMN(Table1)) ) }
This will return number like 3005 where 3 is the row and 5 is the column, so the address is:
{ = ADDRESS( MIN( IF(Table1=MIN(Table1), ROW(Table1)) ),
MOD(MIN( IF(Table1=MIN(Table1), ROW(Table1)*10^5 +COLUMN(Table1)) ), 10^5) ) }
The VBA version will be much simpler, because of the Range.Find method:
Function findMin(r As Range) As Range
Set findMin = r.Find(WorksheetFunction.Min(r))
End Function
with sample uses:
=CELL("address", findMin(Table1))
=ROW(findMin(Table1))
=COLUMN(findMin(Table1))
I'm curious to see how others do this, but, for the sake of example, suppose your data was set up in the range A1:G7. You could do this via the following array function (meaning press CTRL+SHIFT+ENTER after entering the formula) as follows:
=ADDRESS(MIN(IF(ABS(A1:G7)=SMALL(ABS(A1:G7),1),ROW(A1:G7)),MIN(IF(ABS(A1:G7)=SMALL(ABS(A1:G7),1),COLUMN(A1:G7))))
Note that if you wanted the row and column values separately, they are in this formula too:
Row: = MIN(IF(ABS(A1:G7)=SMALL(ABS(A1:G7),1),ROW(A1:G7)))
Col: = MIN(IF(ABS(A1:G7)=SMALL(ABS(A1:G7),1),COLUMN(A1:G7)))
Hope this helps.
UPDATE:
Given the comment made (which I completely missed) that if the value appeared more than once you could get a different result for the row and column values, I made up a new formula that will give you the result you want.
Give this a try:
=CELL("address",INDIRECT(TEXT(SMALL(IF(ABS(B2:GS201)=SMALL(ABS(B2:GS201),1),ROW(B2:GS201)*10^4+COLUMN(B2:GS201)),1), "R0000C0000"),0))