I have this string to match some text using VLOOKUP.
=CONCATENATE(VLOOKUP(D10,Clients!A1:F10034,2),", ",VLOOKUP(D10,Clients!A1:F30034,3),", ",VLOOKUP(D10,Clients!A1:F10034,4),", ",VLOOKUP(D10,Clients!A1:F10034,5))
When it runs into a match that has a full stop in it, the match returns the first result that matches what it has before the full stop.
Eg if the lookup tries to match "C.B.A Solutions" and there is "C Tyres" & "C.B.A Solutions" inside of "Clients!" it will match "C Tyres" because it comes up first.
Your VLOOKUPS are missing the 'optional' forth argument. Note that this forth argument isn't 'optional' unless your data is sorted in ascending order and a match is guaranteed (i.e. your lookup term will always exist in the lookup database). Is that the case here? If so, amend your question to clarify. If not, add 'False' in as a forth argument.
Note that your formula is very inefficient. Most of the work that VLOOKUP does is in locating a matching row in the key column where the lookup term is. Better to relegate that computationally expensive task to a dedicated MATCH function in its own column, and then to feed that result to four INDEX functions.
Put this in a separate column:
=MATCH(D10,Clients!A1:F10034,0)
Then point some INDEX functions at the answer, instead of using computationally expensive VLOOKUP functions:
=CONCATENATE(INDEX(Clients!C1:C30034,[Match Output]),", ",INDEX(Clients!D1:D30034,[Match Output]),,", ",INDEX(Clients!E1:E30034,[Match Output]),)
Replace [Match Output] with the cell containing the output of the MATCH function.
Google INDEX and MATCH vs VLOOKUP for why this matters.
Note that sorting your lookup lists and then ommittig that forth argument and using something called the Double VLOOKUP trick (that handles missing values in your lookup list) will be many thousands of times faster again. See my post at the following link for more:
http://dailydoseofexcel.com/archives/2015/04/23/how-much-faster-is-the-double-vlookup-trick/
Related
I'm trying to make my monthly transaction spreadsheet less work-intensive but I'm running up against problems outputting my category lookups as an array. Right now I have a table with all my monthly transactions and I want to create another table with monthly running totals. What I've been doing is manually summing each entry from each category, but I'd love to automate the process. Here's what I have:
=SUM(INDEX(Transactions[Out], N(IF(1,MATCH(I12,Transactions[Category],FALSE)))))
I've also tried using AGGREGATE in place of SUM but it still only returns the first value in the category. The N(IF()) was supposed to force INDEX to return all the matches as an array, but it's not working. I found that trick online, with no explanation of why it works, so I really don't know how to fix it. Any ideas?
Just in case anyone ever looks at this thread in the future, I was able to find a simpler solution to my problem once I implemented the Transactions[Category]=I12 method. SUM, itself will take an array as an argument, so all I had to do was form an array of the values I wanted to keep from Transactions[Out] range. I did this by adjusting the method Ron described above, but instead of using 1/(Transactions[Category]=I12 I used 1/IF(Transactions[Category]=I12, 1,1000) and surrounded that by a FLOOR(*resulting array*, .01) which rounded all the thousandth's down to zero and didn't yield any #DIV/0! errors.
Then! I realized that the simplest way to get the actual numbers I wanted, rather than messing with INDEX or AGGREGATE, was to multiply the range Transactions[Out] by the binary array from the IF test. Since the range is a table, I know they will always be the same size. And SUM automatically multiplies element by element and then adds for operations like this.
(The result is a "CSE" formula, which I guess isn't everyone's favorite. I'm still not 100% clear on what it means: just that it outputs data in a single cell, rather than over multiple cells. But in this context, SUM should only output a single number, so I'm not sure why I need CSE... A problem for another day!)
In your IF, the value_if_true clause needs to return an array of the desired row numbers from the array.
MATCH does not return an array of values; it only returns a single value which, with the FALSE parameter, will be the first value. That's why INDEX is only returning the first value.
One way to return an array of values:
Transactions[Category]=I12
will return an array of {TRUE,FALSE,FALSE,TRUE,...} depending on if it matches.
You can then multiply that by the Row number to get the relevant row on the worksheet.
Since you are using a table, to obtain the row number in the data body array, you have to subtract the row number of the Header row.
But now we are going to have an array which includes 0's for the non-matching entries, which is not good for us as a row number argument for the INDEX function.
So we get rid of that by using the AGGREGATE function with the ignore errors argument set after we do change the equality test to 1/(Transactions[Category]=I12) which will create DIV/0 errors for the non-matchers.
Putting it all together
=SUM(INDEX(Transactions[Out],AGGREGATE(15,6,1/(Transactions[Category]=I12)*ROW(Transactions)-ROW(Transactions[#Headers]),ROW(INDIRECT("1:"&COUNTIF(Transactions[Category],$I$12))))))
You may need to enter this with CSE depending on your version of Excel.
Also, if you have a lot of these formulas, you may want to change the k argument for AGGREGATE to use the INDEX function (non-volatile) instead of the volatile INDIRECT function.
=SUM(INDEX(Transactions[Out],AGGREGATE(15,6,1/(Transactions[Category]=I12)*ROW(Transactions)-ROW(Transactions[#Headers]),ROW(INDEX($A:$A,1,1):INDEX($A:$A,COUNTIF(Transactions[Category],$I$12),1)))))
Edit
If you have Excel/O365 with dynamic arrays and the FILTER function, you can greatly simplify the above to the normally entered:
=SUM(FILTER(Transactions[Out],Transactions[Category]=I12))
I can not figure out how to put 2 of the same IF statement but with a different result in case is not there then to do the second combination.
=IF(C2737="XXX_SF",INDEX(TMParking_8_24!A:A,MATCH(Tracker!J2737&"xxxshortform",TMParking_8_24!F:F,0)),
The above formula is what I'm looking for. Incase xxxshrotform is not there I would like it to search for a xx5shortform. So I added the below to the second part of the formula:
INDEX(TMParking_8_24!A:A,MATCH(Tracker!J2737&"xx5shortform",TMParking_8_24!F:F,0)))
Within the INDEX the xx5shortform exists but it is not finding it.
Use the IFERROR function to pass control over to a second MATCH function if the first is not found.
=IF(C2737="XXX_SF",
INDEX(TMParking_8_24!A:A,
IFERROR(MATCH(Tracker!J2737&"xxxshortform",TMParking_8_24!F:F,0),
MATCH(Tracker!J2737&"xxshortform",TMParking_8_24!F:F,0))), "")
There was no indication as to what to return if C2737 does not equal XXX_SF nor what to do if the second match does not work.
I've adapted this solution from a couple of years ago:
=LOOKUP(2^15,FIND(Keywords,A2),Categories)
I use this for searching within a description field for keywords in a named list, in order to return a corresponding category from an adjacent named list.
However I do not understand the significance of 2^15. Can someone explain?
Also it's unclear in what order the search operates. If two keyword options were "check" and "deposit," and they were assigned to different categories, but both appeared in the same description field cell, how do I know which will be found first? Is it placement in the string, or order in the list?
2^15 is simply an arbitrarily large number, which lookup attempts to find - when it can't find it, it takes the next lowest number.
Effectively your formula looks at Keywords, and attempts to find the value in A2. For each word that actually matches A2, it provides a non-error message. Then out of the whole list, it attempts to find that line number in categories, resulting in many errors, and a single correct value. Lookup picks the value by using 2^15. Though this seems to be a weird way of doing it; it is likely a holdover of pre-2007, as Lookup is generally used now only for backwards compatibility purposes. Also using 1 instead of 2^15 worked for a couple of simple cases that I tried when writing this up.
Although this question has been asked and answered, (Stack Overflow is where I learned how to implement SP), an issue has come up which I can't figure out.
I'm using SP to sum shipments within a pivot table using a product number (with wild-cards), and a specific date. For instance, part numbers can be "AX10235-HP", "AX11135-HP", "AX10235-HP2", "AX10235-HPSPARE" or TP10101-IBM. (There are a large variety of numbers.)
So in this case I want to sum the qty shipments of "AX???35-HP". I wish to sum just the first 2 parts in my short list. However, the command used causes all the parts to sum except the *-IBM number; as if there was a wild-card at the end of the number. In other words "AX???35-HP" is the same as "AX???35-HP*". I've tried wrapping the value in quotes but it takes uses the quotes literally so fails.
This is the function
SUMPRODUCT((S_PART_DATA)*(ISNUMBER(SEARCH($A6,S_PART_RANGE))*(S_PART_DATES=T$4)))
S_PART_DATA array of Shipments,
S_PART_RANGE array of list of part numbers,
S_PART_DATES array of Dates shipments were made
It works the way you describe because SEARCH function finds $A6 within other text, hence it may not be an exact match - better to use SUMIFS function like this:
=SUMIFS(S_PART_DATA,S_PART_RANGE,$A6,S_PART_DATES,T$4)
Assuming all named ranges are the same size and A6 contains the value AX???35-HP
If that doesn't work try this version
=SUMPRODUCT(S_PART_DATA*ISNUMBER(SEARCH("^"&$A6&"^","^"&S_PART_RANGE&"^"))*(S_PART_DATES=T$4))
concatenating the ^ values means you will [probably] only get exact matches
Just getting started in Excel and I was working with a database extract where I need to count values only if items in another column are unique.
So- below is my starting point:
=SUMPRODUCT(COUNTIF(C3:C94735,{"Sharable Content Object Reference Model 1.2","Authored SCORM/AICC content","Authored External Web Content"}))
what i'd like to figure out is the syntax to do something like this-
=sumproduct (Countif range1 criteria..., where range2 criteria="is unique value")
Am I getting this right? The syntax is a bit confusing, and I'm not sure I've chosen the right functions for the task.
I just had to solve this same problem a week ago.
This method works even when you can't always sort on the grouping column (J in your case). If you can keep the data sorted, #MikeD 's solution will scale better.
Firstly, do you know the FREQUENCY trick for counting unique numbers? FREQUENCY is designed to create histograms. It takes two arrays, 'data' and 'bins'. It sorts 'bins', then creates an output array that's one longer than 'bins'. Then it takes each value in 'data' and determines which bin it belongs in, incrementing the output array accordingly. It returns the array. Here's the important part: If a value appears in 'bins' more than once, any 'data' value meant for that bin goes in the first occurrence. The trick is to use the same array for both 'data' and 'bins'. Think it through, and you'll see that there's one non-zero value in the output for each unique number in the input. Note that it only counts numbers.
In short, I use this:
=SUM(SIGN(FREQUENCY(<array>,<array>)))
to count unique numeric values in <array>
From this, we just need to construct arrays containing numbers where appropriate and text elsewhere.
In the example below, I'm counting unique days when the color is red and the fruit is citrus:
This is my conditional array, returning 1 or true for the rows I'm interested in:
($A$2:$A$10="red")*ISNUMBER(MATCH($B$2:$B$10,{"orange","grapefruit","lemon","lime"},0))
Note that this requires ctrl-shift-enter to be used as an array formula.
Since the value I'm grouping by for uniqueness is text (as is yours), I need to convert it to numeric. I use:
MATCH($C$2:$C$10,$C$2:$C$10,0)
Note that this also requires ctrl-shift-enter
So, this is the array of numeric values within which I'm looking for uniqueness:
IF(($A$2:$A$10="red")*ISNUMBER(MATCH($B$2:$B$10,{"orange","grapefruit","lemon","lime"},0)),MATCH($C$2:$C$10,$C$2:$C$10,0),"")
Now I plug that into my uniqueness counter:
=SUM(SIGN(FREQUENCY(<array>,<array>)))
to get:
=SUM(SIGN(FREQUENCY(
IF(($A$2:$A$10="red")*ISNUMBER(MATCH($B$2:$B$10,{"orange","grapefruit","lemon","lime"},0)),MATCH($C$2:$C$10,$C$2:$C$10,0),""),
IF(($A$2:$A$10="red")*ISNUMBER(MATCH($B$2:$B$10,{"orange","grapefruit","lemon","lime"},0)),MATCH($C$2:$C$10,$C$2:$C$10,0),"")
)))
Again, this must be entered as an array formula using ctrl-shift-enter. Replacing SUM with SUMPRODUCT will not cut it.
In your example, you'd use something like:
=SUM(SIGN(FREQUENCY(
IF(ISNUMBER(MATCH($C$3:$C$94735,{"Sharable Content Object Reference Model 1.2","Authored SCORM/AICC content","Authored External Web Content"},0)),MATCH($J$3:$J$94735,$J$3:$J$94735,0),""),
IF(ISNUMBER(MATCH($C$3:$C$94735,{"Sharable Content Object Reference Model 1.2","Authored SCORM/AICC content","Authored External Web Content"},0)),MATCH($J$3:$J$94735,$J$3:$J$94735,0),"")
)))
I'll note, though, that scaling might be a problem on data sets as large as yours. I tested it on larger data sets, and it was fairly fast on the order of 10k rows, but really slow on the order of 100k rows, such as yours. The internal arrays are plenty fast, but the FREQUENCY function slows down. I'm not sure, but I'd guess it's between O(n log n) and O(n^2) depending on how the sort is implemented.
Maybe this doesn't matter - none of this is volatile, so it'll just need to calculate once upon refreshing the data. If the column data is changing, though, this could be painful.
Asuming the source data is sorted by the key value [A], start with determining the occurence of the key column
B2: =IF(A2=A1;B1+1;1)
Next determine a group sum
C2: =SUMIF($A$2:$A$9;A2;$B$2:$B$9)
A key is unique if its group sum is exactly 1
D2: =(C2=1)
To count records which match a certain criterium AND are unique, include column D in a =IF(AND(D2, [yourcondition];1;0) and sum this column
Another option is to asume a key unique within a sorted list if it is unequal to both its predecessor and successor, so you could find the unique records like
E2: =AND(A2<>A1;A2<>A3)
G2: =IF(AND(E2;F2="this");1;0)
E and G can of course be combined into one single formula (not sure though if that helps ...)
G2(2): =IF(AND(AND(A2<>A1;A2<>A3);F2="this");1;0)
resolving unnecessarily nested AND's:
G2(3): =IF(AND(A2<>A1;A2<>A3;F2="this");1;0)
all formulas in row 2 should be copied down to the end of the list