Need to count contents of cells to produce a knitting pattern - excel

So this needs a bit of detail:
n,X,X,X,n is in cells B5 to F5
I need to get the following output:
1n,3x,1n
for this particular row.
Now the n's and X's represent stitches in knitting with the "n" being the background color and the "x" being the front color.
There is an array of cells B5:F12 representing the rows and stitches, so each row will have a different arrangement of stitches or background color.
I need to avoid vba as this needs to be as stable as possible with the user being my Mum who is 90 years old :) and all she needs is a place to enter the name and the layout (which I have done) and a pattern list for each row (also sorted).
I have started to consider things like:
if(B5=C5,1&B5,"")
But given the n umber of combinations that becomes very long.
Any ideas? Cheers.

You could try:
Formula in H5:
=BYROW(B5:F12,LAMBDA(x,LET(z,REDUCE(VSTACK(TAKE(x,,1),1),DROP(x,,1),LAMBDA(a,b,IF(b=#TAKE(a,,-1),IF(COLUMNS(a)=1,VSTACK(b,TAKE(a,-1)+1),HSTACK(DROP(a,,-1),VSTACK(b,DROP(TAKE(a,,-1),1)+1))),HSTACK(a,VSTACK(b,1))))),TEXTJOIN(",",,DROP(z,1)&TAKE(z,1)))))
I'll see if I can golf the bytecount down a bit...
EDIT:
After a considerable amount of golfing (came down to 119), I came up with:
=BYROW(B5:F12,LAMBDA(x,MID(REDUCE("",x,LAMBDA(a,b,IF(RIGHT(a)=b,LEFT(a,LEN(a)-2)&1+LEFT(RIGHT(a,2)),a&",1")&b)),2,99)))
Though less dynamic than the 1st one, but possible due to the fact there are only <10 columns for each knitting pattern.

If your mother doesn't have the latest Excel (with LAMBDA etc), here is an alternative to #JvdV's answer which only uses LET,SEQUENCE and FILTER.
It only accepts a single row, so you'd need to fill the formula down.
=LET(p,LOWER(B5:F5),c,COLUMNS(p),s,SEQUENCE(,c),
a,IF(s=c,c,IF(INDEX(p,,s)<>INDEX(p,s+1),s,0)),
b,FILTER(a,a>0),t,SEQUENCE(,COLUMNS(b)),
n,IF(t=1,INDEX(b,,t),INDEX(b,,t)-INDEX(b,,t-1)),
TEXTJOIN(",",TRUE,n & INDEX(p,,b)))
I might add that it allows for adding more than one colour into the pattern ...
and with a bit of conditional formatting, the good lady can design her own multicolour patterns!

This is just a start of a solution, but in cell "B6" you can put the formula:
=(IF(B5=A5,A6+1,1))
This will generate following list:
B C D E F
5: n x x x n
6: 1 1 2 3 1
From there, you can try to get the Subtotals feature to work, based on the Max formula, ... (as I said, this is just a start).

If you are willing to spread the logic over multiple sheets, it's quite easy to come up with a way to do this. Consider a workbook with three sheets:
Pattern
EqualPrevCol, where each cell of Pattern is checked for equality against the previous column of the same row.
The formula for cell EqualPrevCol!D3 is:
=Pattern!D3=Pattern!C3
And finally PatternResult, where most of the logic resides:
Consider one row of EqualPrevCol:
At every FALSE column, we want to know how many columns until the next FALSE. To do this, we want to find the next exact MATCH for D3 in the rest of the row:
=MATCH(EqualPrevCol!D3, EqualPrevCol!E3:$H3, 0)
If no match is found, that means the rest of the row is all TRUE. In this situation, we want to return the length of the rest of the row plus this current cell.
=IFNA(MATCH(...), COLUMNS(D3:$H3))
And finally, we append this to the current character:
=IFNA(...) & Pattern!D3
Also, if the 7 row at this column is TRUE, we want to keep this blank:
=IF(EqualPrevCol!D3, "", IFNA(...) & ...)
The full formula of cell PatternResult!D3 is:
=IF(EqualPrevCol!D3, "", IFNA(MATCH(EqualPrevCol!D3, EqualPrevCol!E3:$H3, 0), COLUMNS(D3:$H3)) & Pattern!D3)
Finally, the pattern is condensed to the Pattern sheet. The Pattern!B3 cell contains:
=TEXTJOIN(", ", TRUE, PatternResult!D3:$H3)
To scale this up, you simply need to change all occurrences of $H in the formulas (this was a reference to the last column) and re-fill the cells on the latter two sheets.

Related

excel formula to give the priority to a value from a range of values in a column

This is probably a simple fix (although me thinking this, means it probably isn't), so I apologize in advance if this is mere child's play.
In an excel sheet I am working on, I have a range (for the sake of this example is B1:B10) which can contain one of 5 variables (not including blanks) - OG, D, L, PP or C.
I require a formula in another cell to review the range in question and output a value based on the following rules in this priority:
If OG appears anywhere in the column, regardless of other inputs, display OG;
If D and L and/or PP and/or C appear in the column, display OG;
If only D appears in the column, display D;
If only PP appears in the column, display PP;
If only L appears in the column, display L;
If only C appears in the column, display C; and
If all cells within the column are blank, display blank
For rules 1-6, any blank cells within the column should not be considered. It is only where all cells are blank, i.e. rule 7, that this should be considered.
I have tried IF formulas but have found these only consider a single cell.
I've tried searching everywhere and can't find anything on this (although this is probably down to me not phrasing my question/searches correctly).
Any help would be much appreciated. Thanks in advance!
Use an 'if' formula, but for your condition, Use 'MATCH': for eg, for checking the first case:
=IF(MATCH("OG",$B$1:$B$10,0), "OG", "FALSE")
The above formula will put "OG" if it's in any of the cells, else "FALSE".
In a similar way, change all your logic, but set the conditions to use match to see if they exist somewhere in the column
Here is a possible solution. For your 6 first tests, you type each of these formulas in a cell (I did it from D1 to D6) :
Test 1 (D1)
=IF(COUNTIF(B1:B10;"OG");"OG";"")
Test 2 (D2)
=IF(AND(COUNTIF(B1:B10;"D");OR(COUNTIF(B1:B10;"L");COUNTIF(B1:B10;"C");COUNTIF(B1:B10;"C";"")));"OG";"")
Test 3 (D3)
=IF(COUNTIF(B1:B10;"D")=DCOUNTA(B1:B10);"D";"")
Do the same for test 4 to 6 by replacing "D" by "P","L","C".
Now your target cell :
=IF(D7="empty";"";INDEX(D1:D7;MATCH(TRUE;INDEX((D1:D7<>"");0);0)))
This last cell will simply show the first non empty value of your test cells.
The last test is kind of implicit.
I hope I got your tests right, let me know if not.
EDIT : Sorry for the numerous editings, my Office isn't in English, that's a pain to translate the formulas. They should be working now.
EDIT 2 : Your last test is not implicit and there is a possibility that last cell show "NA". So you should add this to D7 :
=IF(COUNT(B1:B10)=0;"empty";"*A value to show if all tests didn't pass*")
Also now your target cell has D7 in its formula's range.
I feel condition 2 little confusing, Do you mean D is mandatory and other (L,PP,C) are option to result "OG" ?
What should be the result if we have multiple input of (L,PP,C) in the range ? Should it be BLANK?
I came up with this formula if D is mandatory in condition 2 and formula will return Blank if only other 3 inputs are there except "OG" and "D"
Formula: =IF(COUNTIF(B1:B10,"OG")>0,"OG",IF(AND(COUNTIF(B1:B10,"D")>0,SUM(COUNTIF(B1:B10,"D"),COUNTIF(B1:B10,"L"),COUNTIF(B1:B10,"PP"),COUNTIF(B1:B10,"C"))>1),"OG",IF(COUNTIF(B1:B10,"D")=COUNTA(B1:B10),"D",IF(COUNTIF(B1:B10,"L")=COUNTA(B1:B10),"L",IF(COUNTIF(B1:B10,"PP")=COUNTA(B1:B10),"PP",IF(COUNTIF(B1:B10,"C")=COUNTA(B1:B10),"C",""))))))
First Condition:
Condition 2:
Condition 3:
Condition 4:
Condition 5:If there is no "OG" or "D" in the array formula returns Blank.

Concatenate Values from a Range based on a Lookup

I'm working on a budget for a project with multiple phases. There is a possibility that not all phases will be worked on so I've added some lookups and SUMIF formulas so that I can get a summary of my included and excluded effort and dollar amounts. That all works fine. Now I'd like to hide my row of lookups (row 1), but still have a way of identifying which phases of the project are included and which are excluded. Obviously I could manually concatenate them together, but if the phases being included/excluded change then I need to remember to update those formulas (and it's not nearly as fun as doing all in a formula). Here's how my sheet looks:
The TEXTJOIN function seems like it should work (i.e. =TEXTJOIN(CHAR(10), TRUE, C2:N2)), but I can't wrap my head around how to make the range parameter dependent on my lookup row. I played around with INDEX using something like =TEXTJOIN(CHAR(10), TRUE, INDEX(A2:M2,,(A1:M1="Yes")*COLUMN(A1:M1))), but didn't have any luck. At the end of the day I want to have something like:
Phase 1 Phase 2 Phase 5
Please note that the above data should all appear in the same cell - using the line feed character, CHAR(10), as the delimiter in the TEXTJOIN function will make all of the phases appear on a new line within a single cell. I do not want to fill formulas through multiple cells. Thanks in advance for any help.
Please take a look at the picture. I had a similar issue in the past (and brought it to StackOverflow, at which point I was helped by #ScottCraner, original post here:
Doing an array formula lookup
Basically,
1) You set up the array you are looking through - in my case, its $A$2:$A$6, in your case it will be $B$2:$M$2.
2) You then nest the COUNTIFS function inside of a match function. The function does the following:
A) It checks whether the name of phase X has already shown up in column E when you are copy/pasting down
B) If it has, move on to the next one
C) If it hasn't, output
3) Of note: this is an array formula, so the formula itself is checking through every cell. So it looks at cell A2; if the cell in B2 is "Yes", and "Phase 1" isn't in range in column E, then put in phase 1. Because it is, its there. Then it looks at cell A3; if the cell in B3 is "Yes", the same thing for phase 2. Then it looks at cell A4; because B4 is "No", the *(B2:B6="Yes") will throw an error. and so on
4) Place error catching brackets around the function.
A less elegant way to go about this, which doesn't require array formulas would be to use the secondary column's "Yes/No" as an index. This assumes the value in the secondary column is redundant- and repeating the primary column's "Yes" or "No."
In C1: =CONCATENATE(B1,COUNTIFS($A$1:B1,B1)) -
Repeat relatively for E1, G1, etc.
Somewhere separate (the below formula assumes Row 1 of the same worksheet), you could then use: =IFERROR(INDEX($2:$2,MATCH(CONCATENATE("Yes",ROW()),$1:$1,0)-1),"")
To look up "Yes1", returning "Phase 1" and autofill downward. IFERROR is used here to return blank when you run out of "Yes" results.

Excel formula to lookup the last value in a column and return the value of the adjacent cell

I have the following formula to return the value of the last value in a column:
=LOOKUP(2,1/(D:D<>""),D:D)
What I need now is to return the value of the cell adjacent to it as well. (It will not necessarily be the last value in that column and the info in Column D could have duplicates.
If your data looks like this:
A 1
A 2
A 3
B 4
B 5
B 6
C 7
To get last value this will do the trick:
=INDIRECT("B"&COUNTA(A:A))
And to get last where value is A:
=INDIRECT("B"&MATCH("A",A1:A7,0)+COUNTIF(A1:A7,"A")-1)
Just use next column:
=LOOKUP(2,1/(D:D<>""),E:E)
Ok, So I have found an answer by playing around with array formulas.
The problem was that this is a stock control sheet where there are changes made at multiple times, each recorded in the next available row. There is always a date (Column E) but not necessarily a Supplier, as it might be stock moving out. When a Supplier delivers, the Supplier name is recorded in Column D. In D1 the last supplier is then shown with the following formula.
=LOOKUP(2,1/(D:D<>""),D:D)
I want to then see what date it was last received. The formula I found that works is as follows (Array Formula):
=INDEX(E:E,MAX(IF(D:D=D1,ROW(D:D)-ROW(INDEX(D:D,1,1))+1)))
This is generally how I do it:
=XMATCH(FALSE,ISBLANK(A:A),0,-1)
This is what each part does:
Parameter
Explanation
FALSE
Instructs Excel to find the first instance of FALSE that it finds
ISBLANK(A:A)
Takes in the column A:A and notionally assigns a value to every item in the column
0
Means we want an exact match. Probably not necessary to put in, but I think it's good practice anyway
-1
Instructs Excel to start the search at the bottom/right of the range and work up/left. If you change this to 1 (the default), Excel will begin the search at the top/left and work down/right
So, taken together, this will search from the bottom of the column A:A, until Excel finds the first cell that is not blank, and return that cell.
Also, yes, this equation can be changed to a row format (e.g. 1:1), and can take a smaller range (e.g. A1:A20), but it cannot take a 2-dimensional range (e.g. A1:B20).
As a practical matter, this approach is much faster than other approaches (and much faster than you'd think, given it's evaluating against every row/column in the range), and won't get fooled by columns that have empty spaces in them (like with a COUNTA style approach).

Excel Formula with IF... ELSE

Hi all,
I have this excel where by I need to find the location of the item if they are found in column B.
So In my F column, I tried to write ifelse formula which didnt work.which is
=IF(D2="NULL","NONE",C((D2))).
My idea is if D2 is not null, use the value in D column to find the location in C column. In this example, fish no 4, so it is found, my F column should show the value "C" using the value shown in D column and use it as Row no in C column
I hope you guys get the idea and help me out a newbie in excel. Thanks in advance
=vlookup($D2,$A$2:$C$6,3,0)
you can use that in column F. Place that formula in F2 and copy down.
you could technically use it in column E as well, but you would need to change the 3 to a 2.
you did not say what you wanted to do if the D value was "Null" so I am going to take a stab at the dark and wrap you lookup formula in an if statement that will deal with "Null" or empty cells
=IF(OR($D2="NULL",$D2=""),"",VLOOKUP($D2,$A$2:$C$6,3,0))
That is the alternative formula to place in F2 and copy down.
Use the formula:
=IF(D2<>"NULL",VLOOKUP(D2,A2:C6,3,FALSE),"Value is NULL")
Here is the working example:
Put formula in cell F2 and drag it down.
[edit]to pull proper location column, not just the row #[/edit]
Seems like a job for MATCH+OFFSET
Try this formula in cell F2:
=OFFSET($C$1, MATCH(E2,B:B,0)-1, 0, 1, 1)
Match is used to locate the value in the first argument (ie E2) within the range specified in 2nd argument (ie B:B). I use B:B but you could also use range B2:B30 or whatever more specific range you want. (I prefer the more generic B:B, though :) )
Third paramter "0" just indicates "Exact match".
This function will retun "#N/A" if nothing found.
OFFSET takes the result from MATCH to pick out the Location you want. The first parameter in OFFSET is the rows below (or above if negative) from the base row (in this case $C$1). the next is the column: 0 since we're in the column we want to be in. The last two are the size of the range: 1,1 is a 1x1 cell, so just 1 cell. If we did ...,2,3), that would be 2 rows high and 3 columns wide - or a 6 cell range. We're just after 1 cell here.
I've always preferred MATCH + OFFSET to other options, I just found they held up more robustly to changes in a sheet (ie new rows/columns added). So it's mostly personaly preference over VLOOKUP and INDEX. I honestly have never compared their actual performance, however, I've never had any issues with MATCH+OFFSET running slowly :)

SumProduct, doesn't return me text and number. (Only Number)

At first thanks to answer)) (It's important for me :p )
I have a number in A3.
When there is this number in column A (Sheet1), per exemple A7 then it will take the value of the cell B7.
=SOMMEPROD(('Sheet1'!A3:A34=Sheet1!A3)*('Sheet1'!B3:B34))
I use SOMMEPROD, it's working but only with number, and sometimes I have text and number in my cell (column B).
I already changed the format of the cell but doesn't work.
Thanks a lot)))
I think you are saying that some of the values in column B are expressed as text, not as a number, probably because they were imported from another source.
if that is the case: First, convert column B into numbers, Then, use sumproduct.
For example, FIRST convert text to values:
in C3 you would enter
=value(b3)
Then copy that down to from C3 to C34.
Then
=SOMMEPROD(('Sheet1'!A3:A34=Sheet1!A3)*('Sheet1'!C3:C34))
should have the desired effect.
Note that you sometime get #N/A errors with the "value" function, for example if there are unexpected spaces. To be safe, rather than using value alone, try this:
= iferror(value(B3),0)
or to be more creative you can try:
= iferror(value(substitute(B3," ","")),0) ' deletes all spaces
= iferror(value(substitute(substitute(b3,char(160),"")," ","")),0)
'deletes all spaces and "nonbreaking spaces" copied from a web page
It depends on what you're trying to use SumProduct for. There's two main reasons this function shows up. Those are:
To sum the product of two ranges.
To sum a range of numbers that meet multiple criteria. This relies on that True = 1 and False = 0 so when want to find the combined weight of blue dogs in some cells, your formula might look like =SUMPRODUCT(1*($A$1:$A$50 = "Blue"), 1*($B$1:$B$50 = "Dog"), $C$1:$C$50). Note the 1* which guarantees the formula will know how to multiply the results. After all, True and False don't multiply. Their binary representations (1 and 0) though, do.
NB though that people also sometimes remember it as a lookup formula because of the second use, and therefore expect to be able to get text back. Such approaches are an easy misunderstanding to end up with, but really there you want to use an INDEX(<Result Array>,MATCH(1,INDEX(1 * (FIRST CONDITION) * (SECOND CONDITION) * (AND SO ON),,),0). This approach basically gives you an array formula without CTRL-SHIFT-ENTER (it's not faster, but because the condition is in an index formula, it works), and your conditions can be arbitrary (the same way as for sumproduct). But it'll give you the FIRST result, not the sum of all of them.
Hope that helps.
Edit: Crossed my mind, you might be expecting A1 to contain Erp and B1 to contain 54, and in C1 you want Erp54. This doesn't even need a function - just the & operator, which joins two strings together - so in C1, you'd just put =A1 & B1. And you're done.

Resources