Looking for a single ArrayFormula which can populate a matrix calculation where the row and columns are dynamically generated from separate lists.
I have a working ArrayFormula for a single column, but cannot work out how to have this formula auto-populate as new columns are added.
There are separate sheets with Products and Companies. Each Product has attributes Height, Width, and Depth. Each company has criteria for each Height, Width, Depth attribute. A matrix is populated indicating whether a product Height, Width, and Depth fall within the constraints of each company.
Product.Height <= Company.Height AND Product.Width <= Company.Width AND Product.Depth <= Company.Depth
Columns K and L are auto-populated using ArrayFormulas (K3 =query(A3:A,"select A") and L2 =transpose(query(F3:F7,"select F"))) allowing new Products and Companies to be added without having to separately maintain the Matrix.
The ArrayFormula copied across L3:P3 shows the desired result for single Company column:
=arrayformula(
if(
vlookup(indirect("K3:K"&counta($A3:$A)+2),indirect("A3:D"&counta($A3:$A)+2),2,0)<=vlookup(L$2,indirect("F3:I"&counta($F3:$F)+2),2,0),
if(
vlookup(indirect("K3:K"&counta($A3:$A)+2),indirect("A3:D"&counta($A3:$A)+2),3,0)<=vlookup(L$2,indirect("F3:I"&counta($F3:$F)+2),3,0),
if (
vlookup(indirect("K3:K"&counta($A3:$A)+2),indirect("A3:D"&counta($A3:$A)+2),4,0)<=vlookup(L$2,indirect("F3:I"&counta($F3:$F)+2),4,0),
"✔",
"✗"
),
"✗"
),
"✗"
)
)
The goal is to paste a single ArrayFormula in a cell, likely L3, allowing new Companies to be added without needing to manually copy/paste the ArrayFormula across the new Company columns.
The sample sheet combines Products, Companies, and the Matrix into a single sheet for simplicity.
Products A2:D7
Products
Height
Width
Depth
Product 1
10
10
10
Product 2
20
20
20
Product 3
25
30
30
Product 4
30
35
35
Product 5
50
50
50
Companies F2:I7
Company
Height
Width
Depth
Company 1
5
5
5
Company 2
20
20
20
Company 3
25
25
25
Company 4
30
35
35
Company 5
25
25
25
Here's what I would do:
Create another sheet which will list all combinations of Products and Companies.
Use the following formula in cell A2:
=INDEX(SPLIT(FLATTEN(FILTER(Sheet1!A3:A,LEN(Sheet1!A3:A))&"#"&TRANSPOSE(FILTER(Sheet1!F3:F,LEN(Sheet1!F3:F)))),"#"))
In cells C1 to E1 of the new sheet, add the headers Height, Width and Depth.
In cell C2 of the new sheet, add this formula:
=ARRAYFORMULA(IF(VLOOKUP(FILTER(A2:A,LEN(A2:A)),Sheet1!A:D,MATCH(FILTER(C1:1,LEN(C1:1)),Sheet1!A2:D2,0),FALSE)<=VLOOKUP(FILTER(B2:B,LEN(B2:B)),Sheet1!F:I,MATCH(FILTER(C1:1,LEN(C1:1)),Sheet1!F2:I2,0),FALSE),1,0))
This creates a matrix of 1s and 0s; 1 if the company dimension is greater than or equal to the product dimension, and 0 if it is not.
Then in the original sheet, in cell L3, add this formula:
=ARRAYFORMULA(IF(VLOOKUP(FILTER(K3:K,LEN(K3:K)) & FILTER(L2:2,LEN(L2:2)),{Sheet2!A:A & Sheet2!B:B,Sheet2!C:C * Sheet2!D:D * Sheet2!E:E},2,FALSE),"✔","✗"))
This looks up the combination of Product and Company and if all three of the company dimensions are greater than the product dimensions (1 * 1 * 1 = 1), then it shows a check mark, and if not then a cross.
I'm using the cell references in the simplified single sheet you provided, so you'll need to change them obviously.
It's similar to a Sheets challenge that I faced lately, so was glad to share what I found out. Basically, it's easier to have a separate sheet for calculations then use that for a lookup reference.
Related
I am trying to weighted average of available stock ie 888 Items. We operate FIFO so that means I need to start sum from recent date backwards. How do i only select those cells that sum up to available stock balance (888) then sumproduct with the price?
Date Items Recieved Price
9/1/2022 254 $25.00
8/25/2022 242 $25.00
8/18/2022 230 $65.00
8/11/2022 218 $77.00
8/4/2022 206 $45.00
7/28/2022 194 $77.00
7/21/2022 182 $89.00
7/14/2022 737 $74.00
7/7/2022 1292 $86.00
6/30/2022 1847 $87.00
Query, Arrayformula & SUMproduct
You tagged both Excel and Google sheets. They're different. In Excel (Office 365) you can do this using:
=LET(stock,888,
data,B2:C11,
items,INDEX(data,,1),
price,INDEX(data,,2),
cumulative,SCAN(0,items,LAMBDA(a,b,a+b)),
r,XMATCH(stock,cumulative,1),
correction,INDEX(items,r)+stock-INDEX(cumulative,r),
SUMPRODUCT(
IFERROR(
VSTACK(
TAKE(items,r-1),
correction),
correction),
TAKE(price,r)))
stock is the number to sum up to.
data is the range containing both the items and prices.
SCAN is used to get the cumulative sum of all items row-by-row.
XMATCH is used to find the row (r) in the cumulative sum where the value is greater than or equal to the stock value.
r is used to correct the items in that row to the value required to get the cumulative sum up to row r equal to the stock value. (Item in row r + stock - cumulative sum in row r).
I than take the rows before r of the items and add (stack) the correction items value calculated and use that in a SUMPRODUCT with the prices up to r.
If r is the first row it'll throw an error at the TAKE(items,r-1)-part, if so IFERROR makes sure the corrected value is used without stacking it on previous items values.
Edit: since you mentioned FIFO you'd probably be interested to calculate from the bottom up. In this case you could use:
=LET(stock,888,
data,SORT(A2:C11,1,1),
items,INDEX(data,,2),
price,INDEX(data,,3),
cumulative,SCAN(0,items,LAMBDA(a,b,a+b)),
r,XMATCH(stock,cumulative,1),
correction,INDEX(items,r)+stock-INDEX(cumulative,r),
SUMPRODUCT(
IFERROR(
VSTACK(
TAKE(items,r-1),
correction),
correction),
TAKE(price,r)))
It works the same, it just uses an extra column for the data, so it could sort from old (first in) to new.
And it's unclear if you wanted this SUMPRODUCT or the average of it, but that's simply adding /stock to the last argument of LET
I have a table of the following type:
Price
Item 1
Item 2
Item 3
Item 4
50
2
2
1
1
75
1
2
2
2
What I'd like to do in Google Sheets is to (a) sum the number of items with a certain ID in each row, (b) multiply the number with the price in each row, and then (c) sum over the results in each row. So for ID 1, the formula should give 2 x 50 + 1 x 75 = 175, and for ID 2 it should give 2 x 50 + 3 x 75 = 325.
This is straight forward if one breaks this up in two steps by adding additional columns, but I have so many item columns and item IDs that this is infeasible. I looked at ways to use COUNTIF row-wise using arrayformula, but couldn't get it to work in conjunction with the multiplication in each row.
Is there a way to do steps (a-c) in a single formula in Google sheets?
Use MMULT and SUMPRODUCT
with id in row 1 (G1 and G2)
=arrayformula(SUMPRODUCT(mmult(IF($B$2:$E=G1,1,0),transpose(column($B$2:$E)^0)),$A$2:$A))
drag to the right
I'm using Google Sheets for our production price calculation and we are getting new orders with different data every week.
I have all the price calculations sorted out but sometimes there are the same data in orders that already been in the past and I have to manually search for it and use the same price if it exists.
As you can see in the example above, when I enter in the selected cell data "100", I have to check if it already exists in cells above (all three cell in the same row) and if it does enter its price on the cell on the right("=" sign), if it doesn't it could say "new" or be left empty.
I looked at the INDEX and MATCH functions but they don't seem to do the trick.
Do you have any suggestions? Of course the formula should be easily copied to every next cell down when new data and orders come in.
Approach
In this case it's useful to have an index for your table. I created a simple one that concatenates the 3 values you have with the & operator. You can see in the table below for the complete formula. Just drag it down to the whole table to make it automatic.
For the price calculation then I am using a VLOOKUP. It will search for the index generated by the three values in the new row and get the corresponding Price if ti exists. If not, it will print NEW. That's just a placeholder of course, you can edit it as you want. I put the first cell of your table as absolute reference in the VLOOKUP formula so you can drag it down and it will always get its upper (already filled) portion.
Table
INDEX X Y Z Price
11010030 110 100 30 1
500300100 500 300 100 2.3
12030010 120 300 10 1.2
500300100 500 300 100 2.3
12030010 120 300 10 1.2
11010030 110 100 30 1
3004510 300 45 10 NEW
11010030 110 100 30 1
=B10&C10&D10 =IFERROR(VLOOKUP(A10, $A$2:I9,5,0), "NEW")
Based on the correct initial thought by Alessandro, please use the following single arrayformula in cell E2
=ArrayFormula(IF(LEN(A2:A)>0,
IF(LEN(D2:D)>0,
VLOOKUP(A2:A&B2:B&C2:C, {A2:A&B2:B&C2:C,D2:D},2,0),"new"),""))
The formula works as a helper column, only showing you what price to use in column D (if it previously exists) or lets you know that you need to calculate a new one.
Functions used:
VLOOKUP
ArrayFormula
LEN
IF
I have a data set which I would like to take a random sample from and place in to a new sheet. I have one extra constraint / stratification: I would like X examples of each of a given attribute.
For example, if COL A has 5 rows of Apples, 5 rows of Bananas etc., I would like a random sample which includes 2 Apple rows, 2 Banana rows and so on for as many values of COL A as there are.
I am halfway there having got a formula to populate a new sheet with a random sample:
A1: =ArrayFormula(FILTER( SORT('My list of 100000 rows'!A:A ;RANDBETWEEN( 0+ROW('My list of 100000 rows'!A:A) ; ROWS('My list of 100000 rows'!A:A)); TRUE); ROW('My list of 100000 rows'!A:A)<=100))
but this doesn't give me the ability to select a minimum or exact number of instances of each unique attribute.
Any advice is appreciated!
I would like a random sample which includes 2 Apple rows, 2 Banana rows and so on for as many values of COL A as there are.
Insert two columns to the left of your data and in A1:
=choose(randbetween(1,10),"12","13","14","15","23","24","25","34","35","45")
in B1 and copied down to suit:
=countif(C$1:C1,C1)
then :
=query(A:D,"select C,D where B contains '"&left(A1)&"' or B contains '"&right(A1)&"' ")
I have a spreadsheet that I'm starting to use for personal money analysis.
My main sheet is called "transactions" and has headers of Category, Description, Date and Amount (it's basically a check register).
I've created a pivot report off of that sheet that contains sum, min and max of Amount by Category.
I would like to make a custom average function on that pivot report but not sure how to go about it.
What I would like to see is the average amount of negative transactions between positive ones.
My positive transactions are my paychecks and the negative transactions are any spending I do.
An example might help in what I'm trying to do here...
Let's say for category "Food" I have the following transactions (in this order)...
-20
-25
-30
100
-30
-35
-40
I'd like my average to be calculated like this...
( ( (-20 + -25 + -30) / 3 ) + ( (-30 + -35 + -40) / 3 ) ) / 2
Anyone have the slightest idea on how I can enhance my pivot report to do this?
You do it with something like:
=ARRAYFORMULA(AVERAGE(IF(Sheet1!D2:D8<0,Sheet1!D2:D8, 0)))
where column D is the amount of your example and Sheet1 contains the "transactions" of your example.
If you want to fill it for the pivot table (having the category as another criterion) you can check the answer at: https://stackoverflow.com/a/9165254/179529
=SUM(ARRAYFORMULA(((Transactions!$A2:$A)=$A2) * ((Transactions!$D2:$D)>0) * (Transactions!$D2:$D) ))
/
SUM(ARRAYFORMULA(((Transactions!$A2:$A)=$A2) * ((Transactions!$D2:$D)>0) * (1) ))
where $A2 is the cell where you have the category name in the pivot table (The $ will allow you to copy the formula to other columns in you want it per month or other second criterion.
If you want to SUM the element in column D only if they great than 0, you need to have ((Transactions!$D2:$D)>0) as the second argument and (Transactions!$D2:$D) as the 3rd argument (otherwise you will count the cells instead of SUM them).
Since AVERAGE will take blank cells as well, I've used SUM/COUNT instead. Note that COUNT is actually SUM with the 3rd argument as 1.
Also note that if you want to ignore a header line you need to define your columns with Transactions!$D2:$D, to start from the 2nd row.