duplicate for every block - excel

I have this Excel table example:
A B C D
--------------
1 | 1 a 1 x
2 | b 1
3 | c 2
4 | a 3 x
5 | 2 r 4 x
6 | r 4 x
7 | t 1
8 | 4
9 | 3 a 1
10| b 3 x
11| c 3
12| b 6 x
I need to find duplicates (marked with x in column D) for every each block, but only in the context of it's own block (a block is what is found between A1 and A4 - for 1, another block is from A5 to A8 - for 2, and so on). B1=a it's not a duplicate for B9=a, because B9 belongs to block 3 and B1 belongs to block 1. But B1 is a duplicate for B4, they are on the same block, therefore both B1 and B4 should be marked with x.
I'm struggle with dynamic range finding/composition:
Basically I need in column D to find the range (starting with position in D first not empty field in A up, and first not empty field in A down). Eg: in D4 I need to get first non empty in A is A1, and first non empty in A is A5, and construct the range as A1:A5-1.

Use a helper column to avoid the need of an array formula:
In d2 put:
=IF(A2="",D1,A2)
Which will fill in the missing column A values:
Then in E2:
=IF(COUNTIFS(D:D,D2,B:B,B2)>1,"x","")
If you want the array formula:
=IF(COUNTIF(INDEX(B:B,AGGREGATE(14,6,ROW($A$1:INDEX(A:A,ROW()))/($A$1:INDEX(A:A,ROW())<>""),1)):INDEX(B:B,IFERROR(AGGREGATE(15,6,ROW(INDEX(A:A,ROW()+1):INDEX(A:A,MATCH("zzz",B:B)))/(INDEX(A:A,ROW()+1):INDEX(A:A,MATCH("zzz",B:B))<>""),1)-1,MATCH("zzz",B:B))),B2)>1,"x","")

Related

Get last number until specific row in excel

I have an excel spreadsheet that looks like this column:
id
----
1
a
b
c
2
d
e
f
3
g
h
i
1
c
d
e
2
a
d
f
Due to the fact that the numbers aren't really IDs, but group-IDs, the desired output structure is:
id | group_id
----
a | 1
b | 1
c | 1
d | 2
e | 2
f | 2
g | 3
h | 3
i | 3
c | 1
d | 1
e | 1
a | 2
d | 2
f | 2
It occurred to me that I could manipulate the formula to obtain the last non-empty value in some manner:
=LOOKUP(2,1/(B:B<>""),B:B)
I couldn't figure out how to change the internal condition to find the last digit/number value. Note: the original order is essential.
Does anyone have a suggestion?
You could produce the matching numbers for each letter using a spill formula with xlookup on the row numbers like this if you have Excel 365:
=LET(range,A1:A20,
filteredNumbers,FILTER(range,ISNUMBER(range)),
filteredNumberRowNumbers,FILTER(ROW(range),ISNUMBER(range)),
filteredLetterRowNumbers,FILTER(ROW(range),ISTEXT(range)),
XLOOKUP(filteredLetterRowNumbers,filteredNumberRowNumbers,filteredNumbers,,-1))
to get the letters themselves it's just
=FILTER(A1:A20,ISTEXT(A1:A20))
Try to apply SCAN():
Formula in C2:
=FILTER(CHOOSE({1,2},A2:A21,SCAN(0,A2:A21,LAMBDA(a,b,IF(ISNUMBER(b),b,a)))),ISTEXT(A2:A21))
Or, with access to VSTACK() and HSTACK(), to include headers:
=VSTACK({"ID","GROUP_ID"},FILTER(HSTACK(A2:A21,SCAN(0,A2:A21,LAMBDA(a,b,IF(ISNUMBER(b),b,a)))),ISTEXT(A2:A21)))
All the above answers are great. Another option that works for me is:
=LOOKUP(2,1/(ISNUMBER($A$1:A2)),$A$1:A2)
I insert that formula in B2 and use flash fill to reuse each row. Then, I filtered out the rows with letters in the A column.

Highlighting 3 Cells If Condition Met

I have a question regarding conditional formatting in Excel.
I have a sheet that acts as a calendar for my team members whereby calendar dates are in row 1 and each person’s name in column A. Each person occupies 3 rows unmerged, so the first name occupies rows 2 to 4, the next person 5 to 7, and so on. If the person will not be at work on a particular day, a “out of office” will be written on the respective first row. Assuming that 1 January occupies column B and that the first person will be out of office then, the value of cell B2 will be “out of office”. Using conditional formatting, I was able to highlight B2:B4 without issues. However, I was only able to do this for a single person.
I would like to know if there is a way of extending some conditional formatting formula to all 20 members so that I do not have to do the same thing for another 19 times (more if new members join).
So if any cell in column B contains "out of office" then this cell and the next 2 cells below shall be formatted? Or in other words a cell shall be formatted if itself or the cell 1 row above or the cell 2 rows above contains "out of office"?
This can be achieved using the following conditionla formatting rule for whole column B:
Conditional formatting rule based on formula:
=OR(B1="out of office",B1048576="out of office",B1048575="out of office")
Background: In CF the references are like a carousel. So what in B1 is
=OR(B1="out of office",B1048576="out of office",B1048575="out of office")
will be in B2 then
=OR(B2="out of office",B1="out of office",B1048576="out of office")
(B1048576 plus 1 row = B1)
and in B3 then
=OR(B3="out of office",B2="out of office",B1="out of office")
If you are using Conditional Formatting Formula, then you can use the following code to retrieve the value from the current or previous row in the pattern 2, 5, 8, 11, etc:
INDEX(A:A, 3*INT((ROW()-2)/3)+2, 1)
To break it down: Using INDEX(A:A and , 1) will get us a row from Column A (of course, this moves across as your Format Condition does) - the row itself is specified by the ungainly mess in the middle: 3 * INT((ROW() - 2) / 3) + 2
Putting that kludge into plain-text: Start with the current row, subtract 2, round down to a multiple of 3, then add 2 again
Row | Subtract 2 | Round down to 3 | Add 2
1 | -1 | -3 | -1
2 | 0 | 0 | 2
3 | 1 | 0 | 2
4 | 2 | 0 | 2
4 | 3 | 3 | 5
.. | .... | .... | ..
28 | 26 | 24 | 26
29 | 27 | 27 | 29
30 | 28 | 27 | 29
31 | 29 | 27 | 29
32 | 30 | 30 | 32
So - you can now just apply whole-column conditional formatting, with a formula something like this:
=INDEX(A:A, 3*INT((ROW()-2)/3)+2, 1) = "Out of Office"
And it will apply to blocks of 3 rows at a time in each column, starting at Row 2 (or -1)

Excel array formula to find row of largest values based on multiple criteria

Column: A | B | C | D
Row 1: Variable | Margin | Sales | Index
Row 2: banana | 2 | 20 | 1
Row 3: apple | 5 | 10 | 2
Row 4: apple | 10 | 20 | 3
Row 5: apple | 10 | 10 | 4
Row 6: banana | 10 | 15 | 5
Row 7: apple | 10 | 15 | 6
"Variable" sits in column A, row 1.
"Fruit" refers to A2:A6
"Margin" refers to B2:B6
"Sales" refers to C2:C6
"Index" refers to D2:D6
Question:
From the above table, I would like to find the row of two largest "Sales" values when Fruit = "apple" and Margin >= 10. The correct answer would be values from row 3 and 6. I have tried the following methods without success.
I have tried
=LARGE(IF(Fruit="apple",IF(Margin>=10,Sales)),{1,2}) + CSE
and this returns 20 and 15, but not the row.
I have tried
=MATCH(LARGE(IF(Fruit="apple",IF(Margin>=10,sales)),{1,2}),Sales,0)+1
but returns row 2 and 6 as the first matches to come up are the 20 and 15 from "banana" not "apple".
I have tried
=INDEX(D2:D7,LARGE(IF(Fruit="apple",IF(Margin>=10,ROW(Sales)-ROW(INDEX(Sales,1,1))+1)),{1,2}),1)
But this returns row 7 and 5 (i.e. "Index" 6 and 4) as these are just the first occurrences of "apple" starting from the bottom of the table. They are not the largest values.
Can this be done with an Excel formula or do would I need a macro? If macro, can I please get help with the macro? Thank you!
use this formula:
=INDEX(D:D,AGGREGATE(15,6,ROW($A$2:$A$7)/(($B$2:$B$7>=10)*($A$2:$A$7="apple")*($C$2:$C$7 = AGGREGATE(14,6,$C$2:$C$7/(($B$2:$B$7>=10)*($A$2:$A$7="apple")),F2))),1))
I put 1 and 2 in F2 and F3 respectively to find the first and second.
Edit #1
to deal with duplicates we need to add (COUNTIF($G$1:G1,$D$2:$D$7) = 0). The $G$1:G1 needs to refer to the cell directly above the first placement of this formula. So the formula needs to start in at least row 2.
=INDEX(D:D,AGGREGATE(15,6,ROW($A$2:$A$7)/((COUNTIF($G$1:G1,$D$2:$D$7) = 0)*($B$2:$B$7>=10)*($A$2:$A$7="apple")*($C$2:$C$7 = AGGREGATE(14,6,$C$2:$C$7/(($B$2:$B$7>=10)*($A$2:$A$7="apple")),F2))),1))

Excel macro to find a date in a range and then count for next value change in an adjacent column

I am attempting to write a macro to find February 2nd of each year in column A and then count the number of rows (days) until the value in column B changes. This count could be put in a new column, column C, but on the same row as the February 2nd that it correlates to, in this case row 3.
Using the table below the output to C3 would be 5. I am not counting the day of February 2nd but I am counting the day the change occurs. This is for 100+ years that I will need to loop through.
id | A | B | C
----------------------------
1 | 1946/01/31 | 0 |
2 | 1946/02/01 | 0 |
3 | 1946/02/02 | 0 |
4 | 1946/02/03 | 0 |
5 | 1946/02/04 | 0 |
6 | 1946/02/05 | 0 |
7 | 1946/02/06 | 0 |
8 | 1946/02/07 | 2 |
9 | 1946/02/08 | 0 |
The real challenge is to do it with a formula. Well, 2 formulas.
The first formula in cell E2 finds the date 2nd Feb by looking for "02/02" at the end of the text in column B and if it is found it places the contents of C2 in that cell. if it's not found it compares C1 with D1, the 2 cells above to see if they are the same because a match was previously found and if so it takes the contents of the cell above. This results in the zeros you can see in column E between 2nd Feb and the point where column C changes.
Formula for E2 and then autofill down to the end of your data
=IF(AND(MONTH(B2)=2,DAY(B2)=2),C1,IF(AND(E1<>"",E1=C1),E1,""))
Now all we need to do is count the cells in column D by looking for the first non blank cell in column D AND(E1="",E2<>"") and then count all the cells that match that cell. I'm not sure what gap you're expecting to find but you can change the 200 to ensure that you count everything. The last part is to take away 1 so that the 2nd feb row is not being counted.
Formula for D2 and then autofill down to the end of your data
=if(AND(E1="",E2<>""),countif(E2:E200,E2)-1,"")

Why doesn't this formula work?

Consider the following (partial) Excel sheet:
| A | B C D
-+---+------------------
1|id | comp1 comp2 comp3
-+---+------------------
2| 1 | 1 0 0
3| 1 | 1 0 0
4| 2 | 0 1 0
5| 3 | 0 0 1
6| 1 | 1 0 0
7| 3 | 0 0 1
As an example, if filled in all zero's and one's in columns B, C and D by hand. I need to automate this because my dataset is to large to do it all manually. I need, for instance for cell B2, a formula which checks whether value of A2 is similar to company id in cell B1. If so, set a 1, else a 0. Another example: take row 4. It has company id 2 in cell A4 so B4 (comp1) should be 0, C4 1 and D4 0.
I have used the following formula in cell B2, ready to be dragged to all other cells:
=IF($A2=RIGHT(B$1;1);1;0)
However, it puts a 0 in B2. I don't understand, because A2 has value 1, and so does RIGHT(B1;1), so IF(1=1;1;0), so B2 should get value 1. But it doesn't where am I going wrong?
Because right() returns a string and you compare a string to a number. You need to transform that string to a number, e.g. with value(right(...)).

Resources