I wanted to know how to get row and column totals from a 2D array in Excel. This is a fairly common thing to do but I couldn't find an answer to it by searching on row and column totals so I thought it would be worth posting it as a question.
Supposing I wanted to find the lowest column total and highest row total in the following array which is in cells A1:D3:-
1 2 3 4
5 6 7 8
9 10 11 12
my initial thoughts were along the lines of
=min(A1:D3*(column(A1:D3)={1,2,3,4}))
but this kind of simple approach doesn't work. I remembered reading that you had to use mmult in some of these situations and have seen advanced formulae using them but couldn't quite remember how. I shall try and answer my own question but other suggestions are more than welcome.
You can do it with MMULT as you mentioned. The following should work with your setup:
Smallest column
=MIN(MMULT({1,1,1},A1:D3))
Largest row:
=MAX(MMULT(A1:D3,{1;1;1;1}))
Note how many 1s in the array - for the rows calc you need a 1 for each column (i.e. 3) and vica versa for columns. Also note the order of the arrays - it won't work the other way around
Yes you have to mmult to deliver either a column array or row array containing the required totals, then use can use MAX, MIN or any other aggregate function to get the value you require.
Column totals
=MIN(MMULT(TRANSPOSE(ROW(A1:D3))^0,A1:D3))
Row Totals
=MAX(MMULT(A1:D3,TRANSPOSE(COLUMN(A1:D3))^0))
So the idea is that you create a single-row array {1,1,1} and multiply it by the 2D array to end up with an array {15,18,21,24} and take the minimum value from it.
Or create a single-column array {1;1;1;1} and multiply the original array by it to end up with an array {10;26;42} from which you get the maximum value.
Remember that mmult works like the matrix multiplication you might have learned at college where for each cell it works across the cells in the corresponding row of the first array and down the cells of the corresponding column in the second array multiplying each pair and adding them to the total. So the number of columns in the first array must always equal the number of rows in the second array.
These are, as #Scott Craner reminds me, array formulae that have to be entered with
Ctrl Shift Enter
Related
I have a complex formula the produces an Array (10+rows and 10+columns).
For simplicity's sake, let's just say it's =unique(a1:z10)
I'm looking for a formula that can counta() each Row of the array individually. It should basically return a 1-column array that counts the number of values in each row.
Because I will then wrap that in a max() function to see the highest count among them all.
Thanks guys. I hope my question is intelligible.
Let me know if further clarification needed.
The standard way of getting row totals of an m rows by n columns array is
=mmult(<array>,<colvector>)
where <array> is an array of numbers and <colvector> is an array n rows high and one column wide containing all ones.
The standard way of getting <colvector> for a range is
=row(<range>)^0
but this doesn't work for an array because you can only use the row function with a range.
So I think you'd have to generate <colvector> another way - the easiest way is to use Sequence, but unfortunately it means repeating the formula for your <array> to get the column count.
Example
Supposing we choose this as our complex array:
=ArrayFormula(if(mod(sequence(10,10),8),"",sequence(10,10)))
a 10 X 10 array with some spaces in it.
The whole formula to get the row counts would be:
=ArrayFormula(mmult(n(if(mod(sequence(10,10),8),"",sequence(10,10))<>""),
sequence(columns(if(mod(sequence(10,10),7),"",sequence(10,10))))^0))
try:
=MAX(ARRAYFORMULA(MMULT(IFERROR(LEN(B:K)/LEN(B:K), 0), TRANSPOSE(COLUMN(B:K)^0))))
if you want to do it all in one step use:
=MAX(ARRAYFORMULA(MMULT(IFERROR(LEN(B:K)/LEN(B:K), 0),
ROW(INDIRECT("A1:A"&TRANSPOSE(COLUMNS(B:K))))^0)))
where you replace B:K ranges with your formula that outputs the array
I have the following inputs
dataset 1 with tens of thousands of rows and 5 array columns
dataset 2 with tens of thousands of rows and 3 array columns
I want to join/merge (add) the 3th column of dataset 1 to a new 4th array column of dataset 2 for the elements for which the ID is the same (same value in column 1 of dataset 1 and column 1 of dataset 2). Mathematically you can write it like this I think:
dataset2(i,4)=dataset1(find(dataset1(:,1)==c(i,1)),3);
but how to put it in MATLAB?
None of the methods mentioned in the MATLAB help function or elsewhere on the internet seem to work. I have already tried merge, join, ismember, vectors, but I can't solve the problem.
Does someone have any ideas? I know the problem can be solved with for loops, but i'm not allowed to use them, so I am searching for alternatives.
I believe this is what you want
%We keep the index of all the matching rows
%NOTICE: I changed c(i,1) to dataset2(:,1)
%matches_in_col_1 = find(dataset1(:,1)==dataset2(:,1));
%EDIT: HOW TO COMPARE MORE THAN 2 COLUMNS
%if you want to find matches in 4 datasets just use this
matches_in_col_1 = find(dataset1(:,1)==dataset2(:,1)==dataset3(:,1)==dataset4(:,1));
%now copy the values from those rows into the corresponding row
%of datsaset2
dataset2(matches_in_col_1,4) = dataset1(matches_in_col_1,3);
I'm not 100% sure. Why is i present? were you trying a loop implementation? My solution also assumes that c was supposed to be dataset2
trying to do a formula only calculator and trying to avoid a bunch of nested ifs in "hidden" columns.
Basically this is a calculator for COC type of game.
So here is a rough table (not sure how to best make a table here):
A B K M
1 name current level Max Level Next level cost
6 Soldier 2 4 X
where x=IF($K6=B6,0,VLOOKUP($A6,Masterdata!$A$4:$CD$50,32+B6,0)))
the masterdata sheet is just the name some data across several columns, some more data across several columns, and then individual columns that contain a cost starting on column 32.
this works to find the cost of the next level (3) but I would like to do a sum with something like: IF($K6=B6,0,sum(VLOOKUP($A6,Masterdata!$A$4:$CD$50,{32+B6, 33+B6,34+b6},0)))). I can get the array to work if I put in fixed numbers ie, {35, 36, 37} but not {32+B6, 33+B6,34+b6}. Additionally, the array won't dynamically change. such as current level=1, max level=9 will require a larger array than current level =5 max, max level=9. Is there a way of doing this?
Further explanation of 2nd part:
example:
current level =1 max level =9
the formula would be something like: IF($K6=B6,0,sum(VLOOKUP($A6,Masterdata!$A$4:$CD$50,{32,33,34,35,36,37,38,39},0)))) I would require 8 columns in the array to be added.
But if current level is 6 and max level is 9 then it would look something like this:IF($K6=B6,0,sum(VLOOKUP($A6,Masterdata!$A$4:$CD$50,{37,38,39},0))))
I would only require 3 columns returned in the array to be added.
So even if the formula needs to remain IF($K6=B6,0,sum(VLOOKUP($A6,Masterdata!$A$4:$CD$50,{32,33,34,35,36,37,38,39},0)))) I would like to constrain the results to only columns 37,38,39
You should exclude the cell reference from the array of constants. And you will require SUMPRODUCT (or else SUM with CSE) to coerce an array of returns:
=IF($K6=B6,0,SUMPRODUCT(VLOOKUP($A6,Masterdata!$A$4:$CD$50,{32,33,34}+B6,0)))
I'm afraid I don't understand your second query re "the array won't dynamically change".
Regards
So I abandoned the vlookup and went the index match route:
Came up with: =SUM(INDEX(Masterdata!$A$1:$Z$32,MATCH($A26,Masterdata!$A$1:$A$32,0),B26+1+14):INDEX(Masterdata!$A$1:$Z$32,MATCH($A26,Masterdata!$A$1:$A$32,0),E26+14))
Seems to work great.
Basically I am finding the row number that matches my search criteria:MATCH($A26,Masterdata!$A$1:$A$32,0) = 26
I then enter that into an index with an offset of my first column based off my min value:index(range,26,B26+1+14), along with the max value:index(range,26,E26+14) and then sum them together sum(index1:index2)
I have a table in Excel:
A B C D
Day1 Day2 Day3
1 Ron 3 2 2
2 Don 4 2 1
3 Ton 1 5 2
On a different worksheet, I need to produce a table of the type (without using macros):
A B C D
Ron Don Ton
1 Ron - - -
2 Don 8 - -
3 Ton 10 11 -
Where the value is the MAX of each pairs value for each days, summed across all days. So if it was just for 3 names and days, I would just use the formula below with a VLOOKUP to see what the value for each name is on a particular day and copy/paste it for each day. (Side note, actually my project is not that big, so by the time I posted this question, I could have been done with it, but I really want to learn how to do this in a more intelligent way).
=SUM(MAX( VLOOKUP(Table2!$A2,Table1!$A:$D,2,FALSE), VLOOKUP(Table2!B$1,Table1!$A:$D,2,FALSE)), and so on Day2, Day3...
I tried the following:
{=SUM(MAX(VLOOKUP(Table2!$A2,Table1!$A:$D,{2,3,4},FALSE),VLOOKUP(Table2!D$1,Table1!$A:$D,{2,3,4},FALSE)))}
However, apparently the VLOOKUP can't return an array (and INDEX MATCH can't either).
Any help would be much appreciated.
L42 is right - VLOOKUP has trouble returning an array when the lookup value is a range or array but with an array in place of column index number it returns an array no problem
To see that just put a single VLOOKUP in a cell, e.g.
=VLOOKUP($A2,Table1!$A:$D,{2,3,4},0)
then select the cell, press F2 to select the formula and F9 to see the result and you get a result like ={3,2,2}
The problem with your formulas is that MAX just takes the largest value of the six values returned by the two VLOOKUPs, it doesn't compare the two arrays
To do that in a single formula you can use a formula of the following form:
=SUM(IF(array1>array2,array1,array2))
that will compare the 2 arrays and sum the largest value in each position, for your setup that would be a formula like this in Table2 B2
=IF($A2=B$1,"-",SUM(IF(VLOOKUP($A2,Table1!$A:$D,{2,3,4},0)>VLOOKUP(B$1,Table1!$A:$D,{2,3,4},0),VLOOKUP($A2,Table1!$A:$D,{2,3,4},0),VLOOKUP(B$1,Table1!$A:$D,{2,3,4},0))))
confirm with CTRL+SHIFT+ENTER and copy across and down
If you have a larger number of columns then to avoid using {2,3,4,5,6,7,8,9,10......etc.} you can use INDEX/MATCH instead of VLOOKUP like this
=INDEX(Table1!$B:$D,MATCH($A2,Table1!$A:$A,0),0)
Note: INDEX here is returning a range (not an array). The MATCH function determines the row number and a zero as the column argument means you get the whole row returned
What I would like to do is to count the amount of lines that matches criterias to be verified in two arrays.
I can't use VBA, add new columns (for instance a new column with VLOOKUP formula) and preferably use arrays.
I have two separate ranges, each with a ID column for the identifier and other fields with data.
For instance, range 1:
Range 2:
If I had only to check the first range I would do:
={SUM((D4:D7="Red") * (E4:E7="Big"))}
But I don't know how to check also using data from the other range.
How, for example, to count the number of items that are Red, Big and Round by using both Ranges ?
Put this in the cell F4:
=IF((VLOOKUP(C4,$C$11:$D$12,2)="Round")*(D4="Red")*(E4="Big"),1,"")
Note that the behavior of VLOOKUP is that it finds the value up to the first parameter. Since there's no 1 in your second dataset, this first cell is going to show "#N/A", which I don't know how to solve, but when you extend this formula down to also compare the other sample data in the first set, the ID numbers 2 and 4 will show up as "yes" for you.
Edit: You wanted a count of this list. So after this, it should be easy to get a count of cells in this column using the COUNT function.
Try this array formula
=SUM((D4:D7="Red")*(E4:E7="Big")*ISNUMBER(MATCH(C4:C7,IF(D12:D13="Round",C12:C13),0)))
The last part is the added criterion you want - the IF function returns {2,4} [IDs where Data 3 is "Round"] and then you can use MATCH to compare C4:C7 against that. If there is a match you get a NUMBER (instead of #N/A) so you can then use ISNUMBER to get TRUE/FALSE and that feeds in to your original formula - result should be 2