Count numbers in text field - google-sheets

I have a spreadsheet that contains cells similar to this:
AAA Up 3
AAA Down 2
BBB Up 1
BBB Down 3
CCC Up 5
CCC Down 2
So it's always some sort of text, followed by Up or Down, and then how often it went up or down. I'd like to count how many times went up or down. In this example the total of Up would be 9, and Down 7. How do I do that in Excel/Google Sheets? I couldn't find a combination of functions that would help me get this problem solved.
I forgot to mention that each row here is one cell. Or in other words, all of the text above is one column only.
Thank you.

It's straightforward in Google Sheets:
=ArrayFormula(query(split(A:A," "),"select Col2,sum(Col3) where Col3 is not null group by Col2"))

Here is another suggestion.
A single formula, shorter than the one by Erik and more robust than the one by Tom.
=QUERY(INDEX(SPLIT(REGEXEXTRACT(A:A,"\w+ \d+$")," ")),
"select Col1, sum(Col2) where Col2 is not null group by Col1")
Functions used:
QUERY
INDEX
SPLIT
REGEXEXTRACT

If we can assume only 1 or 2 digits in the number field then for Up use:
=SUMPRODUCT(--(RIGHT(A1:A6,2))*ISNUMBER(SEARCH(" Up ",A1:A6)))
and for Down use:
=SUMPRODUCT(--(RIGHT(A1:A6,2))*ISNUMBER(SEARCH(" Down ",A1:A6)))

There are many replies here. I'll suggest another and then tell you why it may be different:
=ArrayFormula(QUERY(SPLIT(REGEXEXTRACT(FILTER(A2:A,A2:A<>"")," ([UpDown]+ \d+)$")," ",0),"Select Col1, SUM(Col2) GROUP BY Col1 Label SUM(Col2) ''"))
It's not clear from your post whether "AAA," "BBB," etc. will be solid blocks of alpha-numeric information in your real application. I can imagine that the opening text might actually be strings with spaces (e.g., "Joe Schmoe from Idaho UP 3"). If so, some of the other formulas I see here will fail; but this formula will account for that.

Though a bit crude, but it'll work. Let us assume your data is in A2:A7 like this
AAAAAA Up 300
AAA Down 2
BBB Up 10
BBB Down 3
CCC Up 5
CCC Down 2
Enter this array formula in cell B2 (and copy downwards) [don't forget to use ctrl+shift+enter)
=VALUE(RIGHT(A2,LEN(A2)-MIN(SEARCH({0,1,2,3,4,5,6,7,8,9},A2&"0123456789"))+1))
Enter Up in C1 , Down in D1 and then enter this formula in C2 (and copy downwards and then rightwards so that cells C2:D7 are filled with this formula)
=--NOT(ISERROR(FIND(C$1,$A2)))
Now to sum Up values - use this formula
=SUMPRODUCT(C2:C7,B2:B7)
and for Down use this
=SUMPRODUCT(D2:D7,B2:B7)
You'll get desired sums

I see that a game of "whose is shorter" has begun. First (for those who don't know), a shorter formula doesn't necessary hold any advantages over a longer one as far as processing ability or speed. In fact, a formula that is a bit longer may hold benefits in terms of ease of understanding, getting rid of superfluous elements, etc.
That said, it seems to be, as I say, a sort of game for people who write formulas often to cut characters. So with only fun in mind, I toss this into the hat as well:
={"Up",SUM(FILTER(SPLIT(A2:A," "),FIND(" Up",A2:A)));"Down",SUM(FILTER(SPLIT(A2:A," "),FIND(" Down",A2:A)))}
It's shorter than the one by marikamitsos and gets rid of the "sum" header, which may or may not be wanted. It also allows for "Up" to be at the top without extra code (or by switching the clauses around, it gains no length and allows for "Down" to be at the top if desired).

Related

Countifs with OR criterias and ranges

I have 5 Columns with color options. I need to COUNT how many of them are different of Black in all options. I mean, the momment they have something different from black in one of the 5 columns, they are consider color. If not, they are considered as black. I.e, if "Red" appears in one of the 5 colums, is COLOR. I have tried to add OR inside Countifs, and using querys but it does not work. The only way I found is using a new columns with if conditions but i need to embed that in the count or query formula (I cannot add any new column in the main datasheet).[ I cannot embed pics yet so there is an screenshot.]
=if(OR(if(AND(L2<>"Black";L2<>"");"COLOR";"")="COLOR";
if(AND(M2<>"Black";M2<>"");"COLOR";"")="COLOR";
if(AND(N2<>"Black";N2<>"");"COLOR";"")="COLOR";
if(AND(O2<>"Black";O2<>"");"COLOR";"")="COLOR";
if(AND(P2<>"Black";P2<>"");"COLOR";"")="COLOR");"COLOR";"BLACK")
I have used that formula as an interface and I can count how many of them are COLOR or BLACK. It works, but I need the result without adding any additional column.
I know that any satement after "comma" in countifs is an "AND" so any range and condition is limiting needing to acomplish all the conditions. I need they work as "ORs" but I did not found a way. I would need something like:
=countifs(AND(L:L,<>"Black"L:L<>"") *OR* AND(M:M,<>"Black"M:M<>"") *OR* AND(N:N,<>"Black"N:N<>"") ...
try:
=INDEX(IF(TRIM(FLATTEN(QUERY(TRANSPOSE(L2:P),,9^9)))="",,
IF(REGEXMATCH(FLATTEN(QUERY(TRANSPOSE(L2:P),,9^9)), "(?i)black"), "BLACK", "COLOR")))
or:
=INDEX(IF(LEN(L2:L&M2:M&N2:N&O2:O&P2:P), UPPER(MAP(L2:L, M2:M, N2:N, O2:O, P2:P,
LAMBDA(L,M,N,O,P, IFS(L="BLACK",L,M="BLACK",M,N="BLACK",N,O="BLACK",O,P="BLACK",P,TRUE,"COLOR")))), ))
update:
=INDEX(QUERY(IF(TRIM(FLATTEN(QUERY(TRANSPOSE(L2:P),,9^9)))="",,
IF(REGEXMATCH(FLATTEN(QUERY(TRANSPOSE(L2:P),,9^9)), "(?i)\bblack\b"), "BLACK", "COLOR")),
"select Col1,count(Col1) where Col1 is not null group by Col1 label count(Col1)''"))
You could do it like this in I2 say
=countif(byrow(L2:P,lambda(r,countifs(r,"<>Black",r,"<>"))),">"&0)
and in J2
=countif(byrow(L2:P,lambda(r,counta(r))),">"&0)-I2
Add a sheet reference if you need the formula to be in a different sheet e.g.
=countif(byrow(Sheet6!L2:P,lambda(r,countifs(r,"<>Black",r,"<>"))),">0")
=countif(byrow(Sheet6!L2:P,lambda(r,counta(r))),">0")-A2
if in A2 and B2 of a separate sheet.
Note
If your database gets large and you get problems with Byrow/Lambda you can revert back to the more conventional Mmult:
=ArrayFormula(countif(mmult(n((L2:P<>"Black")*(L2:P<>"")),sequence(5,1,1,0)),">0"))
and
=ArrayFormula(countif(mmult(n(L2:P<>""),sequence(5,1,1,0)),">0"))-C2
assuming previous formula is in C2.
Use this formula
=ARRAYFORMULA(LAMBDA(u, {UNIQUE(u),COUNTIF(u, "="&UNIQUE(u))})
(LAMBDA(t, IFS(t=FALSE,"Color",t=TRUE,"Black"))
(REGEXMATCH(trim(LAMBDA(f, FILTER(f,f<>""))(FLATTEN(L2:P))), "(?i)black"))))
Demo

Google sheets sum of arrayformula

I want to use arrayformula or filter like with the result of a list of numbers. My question is how to place at the bottom a total of the preceding numbers. The challenge is this is dynamically sized. So when I try to include an option to sum the numbers it doesn't work.
What complicates this even further I would then want to include some numbers below this that aren't included in the sum.
What I tried was this:
={"title"; ArrayFormula; sum of previous cells}
Projects
Title
P1
1
P2
2
P3
1
P4
2
Total
6
Edit: An example that I've used that didn't work out is this:
={arrayformula(if(filter($A2:$A,$A2:A<>"",$A2:$A<>"Total Sum",$A2:$A<>"(to be hired)")="","",{countifs('org 1'!$F$2:$F$1000),"="&filter($A2:$A,$A2:$A<>""),'org 1'!$A$2:$A$1000"),"<>(to be hired)")}));"Total hired"}
Edit:
Here's an example link:
https://docs.google.com/spreadsheets/d/1iBkX1B53vYQVUJ6j8dNOE_ck1dONidsqyNuO0lgSKHw/edit?usp=sharing
I'm using multiple tabs as a reflection to what I'm working with. The tab everything's suppose to show is the Indirect example tab.
I'm using the Source tab as a reference for the tabs I'm targeting. The data tabs is the place I'm drawing the info from.
I'm thinking that I won't be able to do this with ArrayFormula. Probably with Query instead. Not sure what it would look like. If ArrayFormula won't work then a query example would be nice.
see:
={"title"; FILTER(A:A, A:A<>""); SUM(A:A)}
={QUERY({A1:B}, "where Col1 is not null label Col2'title'"); "Total:", SUM(B:B)}

Only apply complex arrayformula() to rows with certain value in dataset

I have a quite complext formula (i mean that is complex to me) that Tom Sharpe helped me building to aggregate values and ordering them by months in a row(you can find the details in the original post but i think you'll only need the final formula which is:
=ArrayFormula(mmult(sequence(1,counta(A2:A),1,0), if((C2:index(C:C,counta(C:C))<=eomonth(G2,sequence(1,datedif(G2,H2,"M")+1,0)))* (D2:index(D:D,counta(D:D))>=eomonth(G2,sequence(1,datedif(G2,H2,"M")+1,0))),E2:index(E:E,counta(E:E)),0)))
and here is the result -> [J1:U1]
Now, what i would need to do as the final step is to be able to group data by a certain label (John or Jane in the example) on separate rows, but mantaining the order/aggregate by month on the row. On the example, this would mean having one row with only 'John' data and below, one with 'Jane' values.
I am struggling to understand how to adapt the formula to do so.
I have tried:
Using another array to first return a list of these labels with query(unique()) or something like that, but then i struggle looping in it with the other formula.
A bit more simplistic but it could work after all: on the 1st row (the cell next to where the data will be returned) writing 'John', on row 2 'Jane' and then using filter() to only pull data that matches. The 'John, Jane' value is for the example but the real labels won't be that many, the list of labels don't need to be dynamic.
The thing with these solutions is that they work when used separately, but i can't figure out how to nest this in the first arrayformula() that Tom helped me with...As i am just beginning with the google sheets queries.
I don't really need necessarily the complete formula/code but maybe just directions or tips to visualize the way i could solve this.
Thanks to all who might contribute
With hindsight I might have done better to go down the route of using a query to calculate the sums on my previous answer rather than Mmult.
This uses the same method as before to create a 2d array of amounts vs dates (going across) and individuals (going down). Then it uses Textjoin to generate a query to group by name with the required number of columns.
=ArrayFormula(query({A2:A,if((C2:C<=eomonth(G2,sequence(1,datedif(G2,H2,"M")+1,0)))* (D2:D>=eomonth(G2,sequence(1,datedif(G2,H2,"M")+1,0))),E2:E,0)},
"select Col1,sum(Col"&textjoin("),sum(Col",,sequence(1,datedif(G2,H2,"M")+1,2))&") where Col1 is not null group by Col1"))
This is the generated query
select Col1,sum(Col2),sum(Col3),sum(Col4),sum(Col5),sum(Col6),sum(Col7),sum(Col8),sum(Col9),sum(Col10),sum(Col11),sum(Col12),sum(Col13) where Col1 is not null group by Col1
Ideally there should be an extra section saying label sum(Col2) '' etc. to suppress the 'Sum' headers.
=ArrayFormula(query({A2:A,if((C2:C<=eomonth(G2,sequence(1,datedif(G2,H2,"M")+1,0)))* (D2:D>=eomonth(G2,sequence(1,datedif(G2,H2,"M")+1,0))),E2:E,0)},
"select Col1,sum(Col"&textjoin("),sum(Col",,sequence(1,datedif(G2,H2,"M")+1,2))&") where Col1 is not null group by Col1 label sum(Col" & textjoin(") '', sum(Col",,sequence(1,datedif(G2,H2,"M")+1,2)) & ") ''"))

Is there a way to join multiple vlookups?

I have a spreadsheet I am entering information from a fundraiser in. I have many parts of it done and it seems like what I'm running into should be easier. I have 3 rows set up for each fundraising program, the first row contains a few pieces of incidental information and then a series of dates/times/dollar amounts. I need to search through this range for every dollar amount that came in at, for example, 7:00 am and add them together. I would like this list to come in starting at L1 in the sample sheet and correspond to the list of times in column K.
I will also need to total all the contributions based on a topic which is the cell under the title of the program - but I should be able to figure that out once I move on to it.
A sample sheet is here: https://docs.google.com/spreadsheets/d/1Kg7XhIgzI0o0uIuGg0RTzv7j_bne8pk6DUwSecIXa9E/edit?usp=sharing
I have tried a variety of formulas using ArrayFormula, VLOOKUP, and filter. I've found examples online using each of those functions that seemed like they should work but didn't. One stopped at the first result it came to and another looked like it was creating a list of what it was found in the cell instead of adding them together.
My current unsuccessful code is:
=vlookup(K1, $H$46:$J$164, 2, 0)
This appears as if it is stopping after encountering the first 0. It's definitely not adding in cell I50
I expect the results for 7:00 am to be $406 but I get $0.
paste in L1 cell:
=ARRAYFORMULA(IFERROR(VLOOKUP(TO_TEXT(K1:K35), TO_TEXT(QUERY({
FILTER(H46:I, MOD(ROW(INDIRECT("A4:A"&ROWS(A46:A)+3)), 4)=0);
FILTER(K46:L, MOD(ROW(INDIRECT("A4:A"&ROWS(A46:A)+3)), 4)=0);
FILTER(N46:O, MOD(ROW(INDIRECT("A4:A"&ROWS(A46:A)+3)), 4)=0);
FILTER(Q46:R, MOD(ROW(INDIRECT("A4:A"&ROWS(A46:A)+3)), 4)=0)},
"select Col1,sum(Col2)
where Col1 is not null
group by Col1
label sum(Col2)''", 0)), 2, 0), 0)*1)

Q: Transpose -> Merge(?) on google sheets

Trying to transpose data such that rows transpose into a single column stacking on top of each other.
=ARRAYFORMULA({TRANSPOSE(A1:C1);TRANSPOSE(A2:C2);TRANSPOSE(A3:C3)})
This formula essentially does what I want but what if I have many more rows? Would I need to enter; TRANSPOSE(Col(x):Col(y)) for every single row?
Any help is appreciated.
Please try:
=TRANSPOSE(SPLIT(TEXTJOIN(",",1,A:C),","))
Notes:
textjoin will join text and skip blanks. Add spaces in column C to have an empty row.
limit of join function is 50000 characters
Max Makhrov's answer is good, but indeed subject to the 50k limit. To get around that, I have recently found another method which is explained in my
interlacing answer to another question
In your case this would look something like this (up to arbitrary 9 rows):
=query(
sort(
{arrayformula({row(A1:A9)*3, A1:A9});
arrayformula({row(B1:B9)*3+1, B1:B9});
arrayformula({row(C1:C9)*3+2, C1:C9})}
),
"select Col2")
Am I missing something, or why does nobody suggest Flatten?
FLATTEN(A1:C3)
And you can use Filter as usual to filter out blank cells, e.g.
=FILTER(FLATTEN(A1:C3);FLATTEN(A1:C3)<>"")

Resources