Related
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.
I am wondering if there is a way to do what I want more automatically, i've been doing it with good old regular copy paste but it's taking a lot of time, I need to take the horizontal data I have currently and put it vertically while keeping the first column for each rows, the first column is my "main" part number and I need to link all the other numbers starting from column B to this main part number, example below,
I sometimes have hundreds of rows and columns to do this for, here is what i'm working with
[1]: https://i.stack.imgur.com/dIyZv.png
And here's what the end result needs to look like;
[2]: https://i.stack.imgur.com/PvxGh.png
Thank you in advance!
It can be achieved either with VBA Code or with formulas. I did it with formulas and will try to show you how below.
I have one sheet with all the data, lets call it Sheet1. It looks like this:
Then, I have another sheet which returns what you want (Sheet2). It looks as follows:
Note that the first two columns are necesary for the formulas to work. The actual result is on Columns C and D.
Now, below are the formulas (or values) you would need to put in Sheet2 to make it work:
Cell A1: 0
Cell B1: 1
Cell A2: IF(B2=1,A1+1,A1)
Cell B2: IF(B1+1=$G$1,1,B1+1)
Cell C1: OFFSET(Sheet1!$A$1,A1,0)
Cell D1: OFFSET(Sheet1!$A$1,A1,B1)
Cell G1: The number of columns in the data on Sheet1
Then, just drag the formulas (not the values in A1, B1), until you have the expected result.
I would suggest you try to implement this simple example first, and then move it to your actual spreadsheet.
Let me know how it goes.
EDIT: Regarding your comment, we could do a trick to make it work for a variable number of columns.
First, lets add some variability to the number of columns in Sheet1. This is how my new Sheet1 looks like:
On Sheet2 I added a formula to count the number of columns per row. See Column F below:
Then, the trick is to change the formulas in Column B in Sheet2:
Before: Cell B2: IF(B1+1=$G$1,1,B1+1)
After: Cell B2: IF(B1+1=OFFSET($F$4,A1,0),1,B1+1)
Note: My formula to count the number of columns per row is:
Cell F4: COUNTA(Sheet1!A1:D1)
Note: Change D1 to the max column in Sheet1. Eg. M1.
Note2: You can get rid of cell G1 now.
Start with column B and everything else becomes a doddle. I only use 1 formula for column B and no more than 1 or 2 for column A (there are 3-4+ methods, no need to duplicate yourself but choose any of them to construct A).
I'm only using 1 formula to make each column. Entire job task done in a minute-5.
Column B. Do this first for all your "column B's":'
=IF(ROW(A1)=1,INDEX(A$1:T$1,INT(((ROW()-20)/20+1-ROW($A$1))/COLUMNS(A$1:T$1))+1,MOD(ROW()-20-ROW($A$1),COLUMNS(A$1:T$1))+1),INDEX(A$1:T$1,INT(((ROW()-20)/20+1-ROW($A$1))/COLUMNS(A$1:T$1))+1,MOD(ROW()-20-ROW($A$1),COLUMNS(A$1:T$1))+1))
So all you have to do is drag down. Change only the row references to refer to your 100's if different rows you need to do this for. 1 minute. Job done
for 30 columns/cells change T to AD, for 200 cells , change T to GR, etc. You can also force it to stop at number of your choice.
If you put it anywhere else, it will still work, but your going to have to jiggy with the math a bit to get it to start from the the first entry in the row ( or the specific Wherever you want). Its up to you.
It acts like a modular clock. Been using it for a few years. Ticker tape. Rolling slabs of concrete laying out for you.
here, this is what I get when I plug it into the first row of any column , referring to a 20 field length header on my sheet.
Etc... It continues forever (or for however long you want it). (and you can change the mod anytime).
The first argument you could change to whatever your requirements are , for instance , if(LEN(F8)<1, or whatever, to Start/"Set the clock."
And For any corresponding ranges (your first column for each) (** Your "Column A's" **):
=IF(LEN(H20)<1,K21,H20)
or you can use this logic. It Becomes elementary.
=IF(J21=K21,J21,J20)
Better if you use this starting from row 2 on each column A: if(and(j1=it's next door neighbour, row(it's next door neighbour cell=1)), it's self j1,.. blah blah blah blah
OR AM I MISSING THE POINT ?
Method for getting column A;
Since you already have B, A becomes a simple trivial matter. Like cell =$fixed$cell , i.e. A1=$B$1 and drag down.
simple. headache over. game over. Its all effortless.
But if you want me to elaborate more ,
method 2 for getting 1st column, column A's;
=IF(LEN(AV1)>1,IF(ROW(AV1)=1,AV1,INDIRECT("Av"&1)),"")
=IF(ROW(B1)=1,B1,INDIRECT("B"&1)) <---- drag down from row 1
Method 1 for getting 1st column;
=IF(LEN(AV1)>1,$AV$1,"") <----- drag down from row 1
Method 3, below was my favourite:
=$B$1 <---- from row1 drag down (where row1 was just = column B, cell b1, a1=b1) easy peasy .
You could always demand a further simplification of M3:
A1=if(len(b1)>1,$b$1,"") <--drag down from b2 (where b1 was already set) *probably best because only returns a value as long as column B is .otherwise returns blank.
It's like handling duplicates by formula. Similar .
there was a method 4 too. bUt its late. (Written # 02:00)
Or did I miss the point? It's easy. Imo
Im only using 2 formulas. 1 for each column you need done . do column B first, and colimn A becomes a matter of fact . A doddle.
method 1 is my new favourite.
Its late, my naighbours have pissed me off again. Pardon my fonts and writing but seriously. didnt expect this. some people need to go to jail.(my naighbours)
So in the end: 1 formula for B. 1 for A (any one of any the 4+ methods. There are more also) , plug in and scroll for all the rows you need this done for . takes you 30 seconds? 5 minutes tops for all your rows.
I am going crazy over this. It seems so simple yet I can't figure this out. I have two worksheets. First worksheet is my data. Second is like an answer key. Upon checking checking, A1:B1 in Sheet 1 is a match with the conditions in Row 52 in SHEET 2, therefore, the value in Column C is "MGC". What is the formula that will perform this function? It's really hard to explain without the data so I pasted a link of the sample spreadsheet. Thank you so much in advance.
sample spreadsheet here. https://docs.google.com/spreadsheets/d/1_AjuNfCdGfEM-XkqPa6W4hSIxQg4NM2Vg4c2C1pQ_vQ/edit?usp=sharing
screenshot here. (wont let me post i have no reputation)
In Sheet2, insert a column in front of Column A and put the formula in A2 =C2&D2.
Then in Sheet1, Cell C2 the formula =vlookup(A2&B2,Sheet2!A:B,2,0).
the first make a concatenated key to lookup, then the second looks up that key.
How about a index(match())? If I've understood correctly you need to match across both the A and B column in sheet one, checking for the relevant values in B and C on sheet 2 to retrun worksheet 2 column a to worksheet 1 column c.
third version try:
=INDEX(Sheet2!$C$1:$C$360,MATCH(Sheet1!A1&Sheet1!B1,Sheet2!$B$1:$B$360&Sheet2!$C$1:$C$360,0))
Basically what this does is use concatenation, the & operator, to specify you are looking for "Criteria A" & "Criteria B" in sheet 1, which makes the string "Criteria A Criteria B", which is supplied in the first part of the match function.
In the second it then says match this against all of my variables in sheet 2 in the same way with concantenation.
The final part of match function (0) specifies you want an 'exact' match
It then supplied this as a reference to the index function, which then finds the row intersecting with the value you want, and returns that.
As noted here https://support.microsoft.com/en-us/kb/59482 this is an array formula, so it behaves differently, and must be input differently. https://support.office.com/en-za/article/Guidelines-and-examples-of-array-formulas-7d94a64e-3ff3-4686-9372-ecfd5caa57c7
There are (at least) 2 ways you could do this without VBA.
USING A SORTED LIST
The first relies on the assumption that your data can be re-sorted, so that everything "Unreported" is in the top, and everything "reported" is together below that (or vice versa). Assuming that this is the case (and it appears to already be sorted like this),we will use the function OFFSET to create a new range which shows only the values that align with either being "Unreported" or "Reported".
Offset takes a given reference to a point on a sheet, and then moves down/up & left/right to see what reference you want to return. Then, it returns a range of cells of a given height, and a given width. Here, we will want to start on Sheet2 at the top left, moving down until we find the term "Unreported" or "Reported". Once that term is found, we will want to move one column to the right (to pull column B from sheet 2), and then have a 'height' of as many rows as there are "unreported" or "reported" cells. This will look as follows in A1 on sheet 1, copied down:
=OFFSET(Sheet2!$A$1,MATCH(A1,Sheet2!A:A,0)-1,1,COUNTIF(Sheet2!A:A,A1),1)
This says: First, start at cell A1 on sheet2. Then find the term in A1 (either "unreported" or "reported", on sheet2!A:A (we subtract 1 because OFFSET starts at A1 - so if your data starts at A1 we need to actually stay at "0". If you have headers on sheet2, you will not need this -1). Then, move 1 column to the right. Go down the rows for as many times as Sheet2 column A has the term found in Sheet1 A1. Stay 1 column wide. Together, this will leave you with a single range on sheet2, showing column B for the entire length that column A matches your term in sheet1 A1.
Now we need to take that OFFSET, and use it to find out when the term in Sheet1 B1 is matched in Sheet2 column B. This will work as follows:
=MATCH(B1,[FORMULA ABOVE],0)
This shows the number of rows down, starting at the special OFFSET array created above, that the term from B1 is matched in column B from sheet2. To use this information to pull the result from column C on sheet 2, we can use the INDEX function, like so:
=INDEX([FORMULA ABOVE],MATCH(B1,[FORMULA ABOVE],0))
Because this would be fairly convoluted to have in a single cell, we can simplify this by using VLOOKUP, which will only require the OFFSET function to be entered a single time. This will work as follows:
=VLOOKUP(B1,[FORMULA ABOVE],2,0)
This takes the OFFSET formula above, finds the matching term in B1, and moves to the 2nd column to get the value from column C in sheet2. Because we are going to use VLOOKUP, the offset formula above will need to be adjusted to provide 2 columns of data instead of 1. Together, this will look as follows:
FINAL FORMULA FOR SHEET1, C1 & COPIED DOWN
=VLOOKUP(B1,OFFSET(Sheet2!$A$1,MATCH(A1,Sheet2!A:A,0)-1,1,COUNTIF(Sheet2!A:A,A1),2),2,0)
OPTION USING ARRAY FORMULAS
The above method will only work if your data is sorted so that the REPORTED and UNREPORTED rows are grouped together. If they cannot be sorted, you can use an ARRAY FORMULA, which essentially takes a formula which would normal apply to a single cell, and runs it over an entire range of cells. It returns an array of results, which must be reduced down to a single value. A basic array formula looks like this [assume for this example that A1 = 1, A2 = 2...A5 = 5]:
=IF(A1:A5>3,A1:A5,"")
Confirm this (and all array functions) by pressing CTRL + SHIFT + ENTER, instead of just ENTER. This looks at each cell from A1:A5, and if the value is bigger than 3, it gives the number from that cell - otherwise, it returns "". In this case, the result would be the array {"";"";"";4;5}. To get the single total of 9, wrap that in a SUM function:
=SUM(IF(A1:A5>3,A1:A5,""))
In your case, we will want to use an array formula to see what row in Sheet2 matches A1 from Sheet1, and B1 from Sheet1. This will look like this:
=IF(Sheet2!$A$1:A$100=A1,IF(Sheet2!$B$1:$B$100,ROW($B$1:$B$100),""),"")
This checks which rows in column A from sheet 2 match A1. For those that do, it then checks which rows in column B from sheet 2 match B1. For those, it pulls the row number from that match. Everything else returns "". Assuming no duplicates, there should only 1 row number which gets returned. To pull that number from the array of results, wrap the whole thing in a MATCH function. Now that you have the row number, you can use an INDEX function to pull the result in Column C with that row, like this:
FINAL ARRAY FORMULA METHOD
=INDEX($C$1:$C$100,MAX(IF(Sheet2!$A$1:A$100=A1,IF(Sheet2!$B$1:$B$100,ROW(Sheet2!$B$1:$B$100),""),"")))
Remember to confirm with CTRL + SHIFT + ENTER instead of just ENTER, when you type this formula. Note that I didn't refer to all of Sheet2!A:A, because array formulas run very slowly over large ranges.
The following formula should work without making any changes to the datasheets.
=INDEX(Sheet2!$A$1:$A$360,MATCH(Sheet1!A1,IF(Sheet2!$C$1:$C$360=Sheet1!B1,Sheet2!$B$1:$B$360),0))
Remember to save this formula as an array with CTRL+SHIFT+ENTER
Documentation on how to use INDEX and MATCH against multiple criteria can be found on Microsoft Support.
It's not clear what you want to do with the multiples that do not have corresponding matches. txed is listed as Unreported twice in Sheet1; kntyctap is listed as Unreported three times. There are only one corresponding match on Sheet2 for each of these.
Non-array Standard Formulas for multiple criteria matches
For Excel 2010 and above use this standard formula in Sheet1!C1:
=IFERROR(INDEX(Sheet2!$A$1:$A$999,AGGREGATE(15,6,ROW(1:999)/((Sheet2!$B$1:$B$999=A2)*(Sheet2!$C$1:$C$999=B1)), COUNTIFS(A$1:A1, A1, B$1:B1, B1))), "")
For version of Excel prior to 2010 use this standard formula in Sheet1!C1:
=IFERROR(INDEX(Sheet2!$A$1:$A$999, SMALL(INDEX(ROW($1:$999)+((Sheet2!$B$1:$B$999<>A1)+(Sheet2!$C$1:$C$999<>B1))*1E+99, , ), COUNTIFS(A$1:A1, A1, B$1:B1, B1))), "")
I've handled error with the IFERROR function in that latter formula. Excel 2003 and previous may have to use an IF(ISERROR(..., ...)) combination.
I have a spreadsheet that has columns for dates and the values can be either "1v, .5v, 1p, .5p, 1s, .5s"
I have 3 columns in each row one for each letter "v, p and s". I want to be able to add the total of all cells in the range grouped by letter and then display the sum for each letter in it's respective column (v, p or c).
Here is an example of the sheet:
Name Vacation Personal Sick 1/5/15 1/6/15 1/7/15 1/8/15
Billy 1.5 1 0 .5v 1v 1p
It is the formula that goes in the vacation/personal/sick cell that I just can't figure out.
I went down the array formula route and came up with essentially the same formula as #Sancho.s :-
=SUM(LEFT($E2:$H2,LEN($E2:$H2)-1)*(RIGHT($E2:$H2)="v"))
You could modify it to take account of blanks:-
=SUM(IF($E2:$H2<>"",LEFT($E2:$H2,LEN($E2:$H2)-1)*(RIGHT($E2:$H2)="v")))
Perhaps this would be better, to ignore any mis-formatted cells:-
=SUM(IFERROR(LEFT($E2:$H2,LEN($E2:$H2)-1)*(RIGHT($E2:$H2)="v"),0))
These all have to be put in with Ctrl-Shift-Enter.
Assuming the range you posted starts at A1, use
=SUMPRODUCT((RIGHT($E2:$G2,1)="v")*LEFT($E2:$G2,LEN($E2:$G2)-1))
in B2. Change "v" and the range to use suitably.
Pro:
It is not an array formula. See why this may be important
Con:
I could not make it work with blank cells.
This "array entered" version will also allow blanks
=SUM(IF(RIGHT(E2:G2)="v",SUBSTITUTE(E2:G2,"v","")+0))
confirmed with CTRL+SHIFT+ENTER
I'd like the count the frequency of identical values in a row. The value must occupy at least two cells and must be beside each other.
I'd like to post the image here but i do not have enough reputations. Anyway, screenshot can be found here: https://www.dropbox.com/s/1em9ltssc1ruw0u/stackOverflow_excelIssue_Countfrequencyofsimilarvaluesinbetweenblankcells.jpg?dl=0
J7:BE7 is where a person will type in the values - it correspond to time, in 30mins increment.
On a different part of the same sheet, in this case DD7:EY7 is where i have the formulas running.
This formula is on (first column) DD7 -- COUNTIF(J7:$BE7,J7)
This formula is on (last column) EY7 -- COUNTIF(BE7:$BE7,BE7)
The formula on DD7 counts the number of times the value on J7 appears across row 7 from column J to BE.
scenario 1: This formula works great if "orange" will only appear once. on my example from K7:L7.
scenario 2: The problem is when "orange" appears again on a non consecutive cell. what i mean is, "orange" appears on K7:L7, then it appears again on P7:Q7.
on scenario 1, the result of the formula in checking K7:L7 is 2, which is the desired value.
on scenario 2, the result of the formula in checking K7:L7 is 4, because it will also count "orange" that appears on K7:L7.
I was hoping the counting will stop if M7 has a different value. K7:L7 contains "orange" and M7:N7 has "apple". or the counting will stop if there's an empty cell in between, like U7:V7 contains "guava", and T7 is empty, then X7:Y7 again has "guava".
the fruits may occupy two to forty-eight columns of each row.
I know this is wordy, but i can't find other ways to explain it, english is not my first tongue.
Thank you in advanced.
~mark
I agree that the question could have been worded a little better, but I think I understand what you're looking for. I can't think of a good way to do it with built-in Excel functions, but if you're willing to make a little use of VBA, you can make a custom function that you can use just like it was a normal function in Excel. You'd just need to add something like this into a new module:
Public Function NumInARow(r As Range) As Variant
Dim i As Integer
If r.Value = "" Or r.Value = Empty Then
NumInARow = ""
Exit Function
End If
If r.Column > 1 Then
If r.Offset(0, -1).Value = r.Value Then
NumInARow = ""
Exit Function
End If
End If
i = 1
Do While r.Offset(0, i).Value = r.Value
i = i + 1
Loop
NumInARow = i
End Function
This function looks at the cell you pass as a parameter, and looks at the cells to the right until it finds a different one and counts the number of identical cells it comes across. For example, if cells A1-C1 all say "Bob" and D1 is blank or has a different value, then if you put =NumInARow(A1) in cell A2, then A2 would show a value of 3. You could drag that formula along the whole cell. The formula leaves the cell blank if the cell it's looking at is not the first in a sequence or if the cell it's looking at is blank. For example, if you put =NumInARow(B1) into cell B2 from the above scenario, B2 would appear blank because the second "Bob" was not the first in the sequence. I hope someone else can think of a way to do this with built-in Excel functions, but this may be an option for you. Here's a WikiHow article to show you how to make/where to put user-defined functions. It's pretty simple if you already have the code.
http://www.wikihow.com/Create-a-User-Defined-Function-in-Microsoft-Excel
The answer which I accepted - using formula - is from G-Man of superuser.com
The thread can be found on this link:
MS Excel: Count frequency of similar values in between blank cells
https://superuser.com/questions/806427/ms-excel-count-frequency-of-similar-values-in-between-blank-cells
This is verbatim of his words:
If I understand your request correctly, the following formulas will work. My solution requires a dummy column and a helper row, but they can be hidden. Further, you can probably eliminate the dummy column with a little bit of work, and you can put the helper row anywhere.
I’ll assume that your client names are in row 2. I’ll use column A as the dummy column, so the appointment data start in column B. Row 3 will be the helper row. In cell B3, enter the formula:
=IF(B2="", "", IF(B2<>C2, 1, C3+1))
Meaning:
If B2="", the client name for this timeslot is blank, so this is an idle timeslot, so display blank.
Otherwise, if B2<>C2, this timeslot and the next have different clients (C2 may or may not be blank), so this is the last timeslot for this appointment. Represent it as 1. Otherwise, count backwards, so the second-to-last timeslot for this appointment is 2, the third-to-last timeslot is 3, etc.
In cell B4, enter:
=IF(A2<>B2, B3, "")
If A2<>B2, this timeslot and the previous one have different clients (A2 may or may not be blank), so this is the first timeslot for this appointment. Display B3, which shows how many timeslots (half hours) there are in this appointment. Otherwise, display blank.
you can find more of his answers on the link I have provided.
Thank you for everyone's help.
Best Regards,
~mark