Can you have wildcard characters in a cell in an IF statement? - excel

I am trying to set up a table that will allow for very quick classification of sites across about 50 different characteristics. The method I have thought of but am unsure if it's possible is as follows.
Worksheet A: the raw data about 100R x 50C with each cell
describing a characteristic of that row where the last column is the
overall classification.
Worksheet B: a table of about 5R x 50C with the columns
corresponding to the columns in Worksheet A.
A row of Worksheet B would look something like:
* | * | * | 1 | * | 3 | * | Y | * | ... | * | * | * |
And a row from Worksheet A that corresponds with this data would look something like:
A | B | C | 1 | 5 | 3 | Z | Y | 1 | ... | F | 2 | X | High Priority
Where the asterisks indicate a wildcard where I don't care what the content is. All of the other cells would be required conditions. Then I was thinking of applying an array formula on the last column to get the classification. Something like:
{=IF(AND(A2:BV2='Worksheet B'!$A$2:$BV$2), "High Priority", "Low Priority")}
But Excel takes the asterisks as literal string content and evaluates it as FALSE.
Is there a way to make this work? Or an alternative method that would be just as simple to implement?

I got to the bottom of it with a reasonably elegant solution. Please post criticisms if there is a situation where this won't work.
={IF(SUM(IF(A2:BV2='Worksheet B'!A2:BV2,0,1))=COUNTIF('Worksheet B'!A2:BW2,"x"),"Top Priority", "Low Priority")}
Where x is for those cells in which I don't care about the outcome. So instead of "*", I am using "x" in the cells above such that Worksheet B is more like:
x | x | x | 1 | x | 3 | x | Y | x | ... | x | x | x |
If anyone is interested, the formula works by counting all of the mismatched elements and checking them against the number of cells with "x" in the result. If these two numbers are equal, the number of mismatches is equal to the number of cells we don't care about.

Related

Formula to multiply all rows in a column after adding 1 to each one of them, and subtracting 1 after all of the products

How can I automate this formula to a large number of cells without needing to manually summing them?
I want to add 1 to each row in a column and then multiply it by the other rows with the same criteria, and after all, I want to subtract 1 of the total value, like this:
=(C2+1)*(C3+1)*(C4+1)*(C5+1)*(C6+1)-1
google-sheets only:
PRODUCT of C2:C6+1 enforcing array context with ARRAYFORMULA:
=ARRAYFORMULA(PRODUCT(C2:C6+1))-1
THis should work:
=EXP(SUMPRODUCT(LN(C2:C+1)))-1
You can do this using two helper columns, where the first one contains the product, and the second the product minus one:
| A | B | C | D | E
==+===+===+====+============+======
1 | | | | 1 | =D1-1
2 | | | x1 | =D1*(C2+1) | =D2-1
3 | | | x2 | =D2*(C3+1) | =D3-1
4 | | | x3 | =D3*(C4+1) | =D4-1
5 | | | x4 | =D4*(C5+1) | =D5-1
Dragging the formulas down should fill them in as expected. Column "E" contains the information you're looking for.

Spreadsheet Formula to Sum Values Over A if B is not in a List of Values

I have a table that looks the following:
| A | B | C |
| 40 | 1 | 1 |
| 180 | 2 | 2 |
| 34 | 1 |
| 2345 | 3 |
| 23 | 1 |
| 1 | 2 |
| 4354 | 3 |
| 2 | 2 |
| 343 | 4 |
| 2 | 2 |
| 45 | 1 |
| 23 | 1 |
| 4556 | 3 |
I want to get the sum of all fields in A where B is neither 1 nor 2 or any other value from colum C. This column contains the values of B where values from A should not be considered for the sum.
I do not know which values B might contain, those values are random and could grow larger, I just wanted to make the example small. My current solution is
{=SUMIF(B1:B13,C1:C2,A1:A13)}
so i can set the lines that should be excluded from the sum in column C. Unfortunately, the current solution does not solve my problem but something different -- it sums up the corresponding entries by value in C. My preferred solution would look something like
=SUMIF(B1:B13,"<>{1, 2}",A1:A13)
=SUMIF(B1:B13,"<>"&C1:C2,A1:A13)
if that were possible (it isn't). I would like to have:
a field (with a list, for example) or column where i can put in the values of B that I do not want to be part of the sum over A.
a method that works with Open Office as well as Excel. I prefer an OO solution.
You could use an array formula so that you can multiply each value in A with a condition. That condition can be any valid Excel formula, so, for instance, you could use MATCH to test if the B value occurs in C:
=SUM((A1:A13)*ISNA(MATCH(B1:B13,$C:$C,0)))
The ISNA function returns TRUE when the match fails, which in a multiplication is used as a numerical value 1. FALSE will make the product 0.
Make sure to enter this as an array formula with Ctrl+Shift+Enter

Counting the frequency of combinations of numbers (in excel using VBA)

I want excel to count the FREQUENCY that certain number-letter combinations appear down a column in excel (using vba). All my data goes down one column like this:
Column A (only 1,2,3,4,5,s,f appear)
1
2
s
4
3
s
4
2
f
2
s
2
s
I want to count the number of occasions combinations of (1-s, 2-s, 3-s, 4-s, 5-s) occur, strictly when the number occurs first (is in the higher row). I do not want to count occasions when the s comes before the number (e.g. s-2). I know how to count the number of individual letters/numbers using the countIf function.
I might later want to expand my analysis to look at the occasions that three letter-number combinations (e.g. 2-s-3, 2-s-5)
I am very much a VBA noob.
Try inserting a new column to the right of Column A. Use this formula =A1&A2 and fill it down the column. The values will look like this:
+----------+----------+
| Column A | Column B |
+----------+----------+
| 1 | 12 |
| 2 | 2s |
| s | s4 |
| 4 | 43 |
| 3 | 3s |
| s | s4 |
| 4 | 42 |
| 2 | 2f |
| f | f2 |
| 2 | 2s |
| s | s2 |
| 2 | 2s |
| s | s |
+----------+----------+
Now you can count occurences like you were doing before! :D
Of course, you can expand to three character frequency analysis by making the formula =A1&A2&A3.
Seems possible with COUNTIFS, with 1 to 5 inclusive in C1:G1 and in C2:
=COUNTIFS($A1:$A12,C1,$A2:$A13,"s")
copied across to suit.
You can use the VBA equivalent of this formula
=SUMPRODUCT(--(ISNUMBER(A1:A12)),--(A2:A13="s"))
which looks for number, followed by s in the row below (4 for your sample)
code
MsgBox Evaluate("SUMPRODUCT(--(ISNUMBER(A1:A12)),--(A2:A13=""s""))")

Excel Formula Optimisation

I am no excel expert and after some research have come up with this formula to look at two sets of the same data from different times. It then displays new entries that are in the latest list of data but not in the old list.
This is my formula:
{=IF(ROWS(L$4:L8)<=(SUMPRODUCT(--ISNA(MATCH($E$1:$E$2500,List1!$E$1:$E$2500,0)))),
INDEX(E$1:E$2500,
SMALL(IF(ISNA(MATCH($E$1:$E$2500&$F$1:$F$2500,List1!$E$1:$E$2500&List1!$F$1:$F$2500,0)),
ROW($F$1:$F$2500)-ROW($F$1)+1),ROWS(L$4:L8))),"")}
Are there any optimisation techniques I could employ to speed up the calculation?
As requested
Some example data(link to a spreadsheet):
https://docs.google.com/file/d/0B186C84TADzrMlpmelJoRHN2TVU/edit?usp=sharing
On this scaled down version its more efficent but on my actual sheet with a lot more data it is slowed.
Well, I was playing around a bit and I think that this works the same, and without the first IF statement:
=IFERROR(INDEX(A$1:A$2500,SMALL(IF(ISNA(MATCH($A$1:$A$2500&$B$1:$B$2500,List1!$A$1:$A$2500&List1!$B$1:$B$2500,0)),ROW($B$1:$B$2500)-ROW($B$1)+1),ROWS(F$2:F2))),"")
That part in your sample data:
ROWS(F$2:F2)<=(SUMPRODUCT(--ISNA(MATCH($A$1:$A$2500,List1!$A$1:$A$2500,0))))
As I understood it, it only sees to it that the row number in which the formula is entered is lower than the number of 'new' items, but it doesn't serve any purpose because when you drag the formula more than required, you still get errors instead of the expected blank. So I thought it could be removed altogether (after trying to substitute it with COUNTA() instead) and use an IFERROR() on the part directly fetching the details.
EDIT: Scratched that out. See barry houdini's comment for the importance of those parts.
Next, you had this:
ROW($B$1:$B$2500)-ROW($B$1)+1
-ROW($B$1)+1 always returns 0, so I didn't find any use to it and removed it altogether.
It's still quite long and takes some time I guess, but I believe it should be faster than previously by a notch :)
A relatively fast solution is to add a multi-cell array formula in a column alongside List 2
{=MATCH($A$1:$A$16,List1!$A$1:$A$11,0)}
and filter the resultant output for #N/A.
(Or see Compare.Lists vs VLOOKUP for my commercial solution)
Array formula is slow. When you have thousands of array formula, it will make the speed very slow. Thus the key will be to avoid any array formula.
The following will be my way to achieve it, using only simple formula. It should be fast enough if you only have 2500 rows.
Column F and H are "Keys", created by concatenating your 2 columns (E and F in your original formula)
Assuming the first line of data is on row 3.
Data:
| A | B | | D | E | F | | H |
| index | final value | | ID | exist in Old? | Key (New) | | Key (Old) |
--------------------------------------------------------------------------------
| 1 | XXX-33 | | 0 | 3 | OOD-06 | | OOC-01 |
| 2 | ZZZ-66 | | 0 | 1 | OOC-01 | | OOC-02 |
| 3 | ZZZ-77 | | 1 | N/A | XXX-33 | | OOD-06 |
| 4 | | | 1 | 4 | OOE-01 | | OOE-01 |
| 5 | | | 1 | 2 | OOC-02 | | OOF-03 |
| 6 | | | 2 | N/A | ZZZ-66 | | |
| 7 | | | 3 | N/A | ZZZ-77 | | |
Column E "exist in Old?": test if the new key (Column F) exists in the old list (Column H)
=MATCH(F3, $H$3:$H$2500, 0)
Column D "ID": to increment by one whenever a new item is found
=IF(ISNA(E3), 1, 0)+IF(ISNUMBER(D2), D2, 0)
the 2nd part of ISNUMBER is just for the first row, where just using D2 can cause an error
Column A "index": just a plain series starting from 1 (until the length of new list Column F)
Column B "final value": to find the new key by matching column A to Column D.
=IF(A3>MAX($D$3:$D$2500), "", INDEX($F$3:$F$2500, MATCH(A3, $D$3:$D$2500, 0))
This column B will be the list you want.
If it is still too slow, there exists some dirty tricks to speed up the calculation, e.g. by utilizing a sorted list with MATCH( , , 1) instead of MATCH( , , 0).

return values from multiple matching rows

First off, I'd like to do this without VB if possible, so I don't have to go through the hassle of teaching recipients how to enable macros.
Now, I believe what I'd like to do is simple, but the answer may be complex formula-wise. I'm trying to list out in new columns the values from a specified column in rows which have matching values from two other columns. Sounds tricky I'm sure, but an example should help immensely...
Say I have the following data:
------------------
| sts | pos | bye |
------------------
| 0 | QB | 8 |
| 2 | WR | 3 |
| 2 | QB | 10 |
| 0 | QB | 4 |
| 2 | QB | 7 |
| 0 | WR | 11 |
| 2 | WR | 9 |
| 2 | QB | 5 |
------------------
That's my source. I want to list out the bye value from all rows that have sts = 2, for each respective pos. In other words, from the source data above I'd want to see the following result set:
--------------------------
| pos | byes |
--------------------------
| QB | 10 | 7 | 5 | |
| WR | 3 | 9 | | |
--------------------------
...because those are the bye values in the rows with sts = 2 and pos equal to the corresponding pos in the result table.
Again, I'd like to avoid macros if possible, and just use a formula in the bye cells of the results table.
Hopefully that makes enough sense for you to take a stab at it. Thanks!
FOLLOW-UP:
#Richard-Morgan I attempted to use your formula but can't get it to work. Here is a screenshot of my actual spreadsheet so we can use real cell references:
So sts is B2:B303, pos is D2:D303, and bye is E2:E303. So then I'd like to list out the byes in columns U thru Y. It looks like your answer, if I'm smart enough to implement it, will get me what I need, so any assistance you can provide to get me to the finish line is greatly appreciated!
Something along the lines of the following could be used:
{=INDEX(tbl, SMALL(IF(COUNTIF(G$3, $A$2:$A$9)
*COUNTIF(G$4, $B$2:$B$9), ROW(tbl)-MIN(ROW(tbl))+1), ROW($C1)), COLUMN($C1))}
where the A column is sts, B column is pos, and C column is bye. The variable tbl is the range of data (not the headers). G$3 would be the sts filter and G$4 is the pos filter.
Copy the array formula DOWN to find all the matching byes; #NUM! will appear after finding no more matches. If this bothers your users, you can add an ISERROR or a tricky conditional format that makes the text white on white.
You can then copy over the formula to the next column and enter new filter values.
G H
sts Search 2 2
pos Search QB WR
10 3
7 9
5 #NUM!
#NUM!#NUM!
If your users are comfortable with pivot tables, using them would be much easier, I would think.
EDIT
Making the formula "transpose" is a bit tricky and I am not having any breakthrough on how to fix that. However, if you want to manually edit the column formulas, here is what you want.
(I made the assumption that S is the sts filter. Maybe you're just doing a count there, but I didn't see where you enter the filter for sts. If S isn't the sts filter, update the formulas to point to where sts is 2 or whatever.)
U2:
{=INDEX(tbl, SMALL(IF(COUNTIF($S2, $B$2:$B$303)*COUNTIF($R2, $D$2:$D$303),
ROW(tbl)-MIN(ROW(tbl))+1), ROW($D$1)), COLUMN($D$1))}
V2:
{=INDEX(tbl, SMALL(IF(COUNTIF($S2, $B$2:$B$303)*COUNTIF($R2, $D$2:$D$303),
ROW(tbl)-MIN(ROW(tbl))+1), ROW($D$2)), COLUMN($D$2))}
etc.
This allows the cells to be copied down.
I am sure there is a way to INDIRECT the ROW/COLUMN, but I ran out of time to look at this at the moment.
EDIT 2
If you put a simple number increment somewhere, let's say U1 has 1, V1 has 2, W1 has 3, etc., you could use the following:
{=INDEX(tbl, SMALL(IF(COUNTIF($S2, $B$2:$B$9)*COUNTIF($R2, $D$2:$D$9),
ROW(tbl)-MIN(ROW(tbl))+1), U$1), COLUMN($D$1))}
This will copy down and across.
This sounds like a job for pivot tables and go to special. You need to add an ID # column though. Here is one way you could do it:
Then once the blanks are selected using go to special you just need to delete them and shift cells left.
Good Luck.
OK I figured out a way to get my desired results. It isn't the cleanest or best way, but it achieves my goal of listing the results horizontally, and avoids macros or pivot tables.
I use a hidden worksheet to list out all the pos and sts values, concatenated as a single value. So...
sts | pos | bye
----------------------
2 | QB | 8
2 | RB | 5
2 | QB | 11
0 | WR | 7
. . .
...becomes....
D | E
-----------
5 | 2QB | 8
6 | 2RB | 5
7 | 2QB | 11
8 | 0WR | 7
. . .
Then, I have a "shadow" results area that mimics the results area on my front-page worksheet. It looks like so:
G | H | I | J | K
-----------------------------
5 | QB | | | | |
6 | RB | | | | |
7 | WR | | | | | . . .
In H5:H7, I have the following formula:
=IFERROR((ADDRESS(MATCH("2"&$G5,$D$5:$D$305,0)+4,COLUMN($E5),4)),"")
This returns the first cell reference it finds in the concatenated column that starts with 2 and ends with the value in column G (e.g. the formulas in row 5 are looking for "2QB").
Then, in I5:n7 I have the following modified formula:
=IFERROR(ADDRESS(MATCH("2"&$G5,INDIRECT(ADDRESS(ROW(INDIRECT(H5))+1,4)&":$d$"&MAX(305,ROW(INDIRECT(H5))+1)),0)+ROW(INDIRECT(H5)),COLUMN($E5),4),"")
The reason I modify the subsequent columns is to change the range in which the formula is looking for its value to start at the next row after the previously found value. For example, with the data above, the formula in H5 would look for "2QB" in D5:D*n*, and return the first row it finds and attach it to column E, which would be E5.
The formula in I5 would then look for "2QB" starting in D*6* instead of D5, a row after the row referenced in H5's result.
Hopefully that made sense.
So what I end up with in my hidden worksheet is this:
G | H | I | J | K
-----------------------------
5 | QB | E5 | E7 | | |
6 | RB | E6 | | | |
7 | WR | | | | | . . .
Then, on my front page worksheet, I simply get the values (the bye) referenced by the cells in H5:*n*7 using:
=IFERROR(INDIRECT(lookups!H5),"")
...which gives me my final result:
G | H | I | J | K
-----------------------------
5 | QB | 8 | 11 | | |
6 | RB | 5 | | | |
7 | WR | | | | | . . .
Like I said, it's totally convoluted, but it works, and I can always refine it later if I figure out how. :) Thanks to you who took a swing at this seemingly complex problem for me! I'm sure your answers work beautifully as well.

Resources