Average of updating entries with chosen columns - google-sheets

Given a sheet like this:
+ ------ + ------- + ---------- + ---------- + ---------- + ---------- +
| A | B | C | D | E | F |
+ -------+ ------- + ---------- + ---------- + ---------- + ---------- +
| AVG | ITEMS | Week 3 May | Week 2 May | Week 1 May | Week 5 Apr |
|=QUERY()| Item 1 | 1263 | 1255 | 1142 | 956 |
| | Item 2 | 1371 | 1263 | 1023 | 1120 |
| | Item 3 | 1382 | 1257 | 1352 | 1853 |
| | Item 4 | 1429 | 1281 | 1120 | 1869 |
I need to move the column B to the first column (A).
Make a script to add a new colum for new entries.
1.-
In AVG column (column A in the example above) there is an average using the formula:
=QUERY(transpose(query(transpose(B2:$F),"Select "&REGEXREPLACE(join("",ArrayFormula(if(len(B2:B),"Avg(Col"&ROW($C2:$C)-ROW($C2)+1&"),",""))), ".\z","")&"")),"Select Col2")
This formula calculates the average of the last 4 weeks only if there's an entry in column B
I need to move this column to the right of the Items list (column B) but when I try to, the formula shows a circular dependency error. Is there a way to tell the formula to only pick the columns I want to?
2.-
There's also a button with an assigned macro to make a new column on the left of the latest week for new entries and insert the week number and month, this is the script:
function onEdit() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('C:C').activate();
spreadsheet.getActiveSheet().insertColumnsBefore(spreadsheet.getActiveRange().getColumn(), 1);
spreadsheet.getActiveRange().offset(0, 0, spreadsheet.getActiveRange().getNumRows(), 1).activate();
spreadsheet.getRange('C1').activate()
.setFormula('=CONCATENATE("Week ",(WEEKNUM(TODAY(),2)-WEEKNUM(EOMONTH(TODAY(),-1)+1)+1)," ",CHOOSE(MONTH(TODAY()),"Jan","Feb","Mar","Apr","May","Jun","Jul","Ago","Sep","Oct","Nov","Dec"))');
};
So it becomes something like this:
+ ------ + ------- + ---------- + ---------- + ---------- + ---------- + ---------- +
| A | B | C | D | E | F | G |
+ -------+ ------- + ---------- + ---------- + ---------- + ---------- + ---------- +
| AVG | ITEMS | Week X MMM | Week 3 May | Week 2 May | Week 1 May | Week 5 Apr |
| | Item 1 | (NEW WEEK) | 1263 | 1255 | 1142 | 956 |
and this is the formula I am using for the week number:
=CONCATENATE("Week ",(WEEKNUM(TODAY(),2)-WEEKNUM(EOMONTH(TODAY(),-1)+1)+1)," ",CHOOSE(MONTH(TODAY()),"Jan","Feb","Mar","Apr","May","Jun","Jul","Ago","Sep","Oct","Nov","Dec"))
The problem with the formula is that uses TODAY() function, which has a variable value while I need a static value. Also when using the script the Conditional Formatting is not carried over in the new column. How can I improve the script?

For replacing TODAY() with a static value, use the Javascript date methods and format the date according to your spreadsheet setting with Utilities.formatDate()
Replace the formula part TODAY() with the variable containing the date object as explained above
Sample:
function onEdit() {
var spreadsheet = SpreadsheetApp.getActive();
var now = new Date();
var today = '"' + Utilities.formatDate(now, spreadsheet.getSpreadsheetTimeZone(), "MM/dd/yyyy") + '"';
spreadsheet.getRange('C:C').activate();
spreadsheet.getActiveSheet().insertColumnsBefore(spreadsheet.getActiveRange().getColumn(), 1);
spreadsheet.getActiveRange().offset(0, 0, spreadsheet.getActiveRange().getNumRows(), 1).activate();
spreadsheet.getRange('C1').activate()
.setFormula('=CONCATENATE("Week ",(WEEKNUM(' +today + ',2)-WEEKNUM(EOMONTH(' + today + ',-1)+1)+1)," ",CHOOSE(MONTH(' + today + '),"Jan","Feb","Mar","Apr","May","Jun","Jul","Ago","Sep","Oct","Nov","Dec"))');
};
Note: If your spreadsheet date format is no "MM/dd/yyyy" - modify formatDate(date, timeZone, format) accordingly, see here
The conditional formatting has to be set separately from setFormula, see here for a sample.

Related

How to translate COUNTIFS formula in ARRAYFORMULA to automatically insert the formula in each row

With my countifs formula in column C I want to auto-number (running total) all occurrences of an identical string in column A (e.g. Apple or Orange) but only if on the same row where the string appears column B is of a certain type, e.g. if in column B the type is of "fruit" in column C auto number all occurrences of an identical string in column A. For each new string which is of type "fruit" start the numbering all over again.
The outcome should be like this:
+---+-----------+-------+---+--+
| | A | B | C | |
+---+-----------+-------+---+--+
| 1 | Apple | Fruit | 1 | |
| 2 | Apple | Fruit | 2 | |
| 3 | Mercedes | Car | 0 | |
| 4 | Mercedes | Car | 0 | |
| 5 | Orange | Fruit | 1 | |
| 6 | Orange | Fruit | 2 | |
| 7 | Apple | Fruit | 3 | |
+---+-----------+-------+---+--+
The formula in column C:
=COUNTIFS($A1:$A$1;A1;$B1:$B$1;"Fruit")
=COUNTIFS($A$1:$A2;A2;$B$1:$B2;"Fruit")
=COUNTIFS($A$1:$A3;A3;$A$1:$A3;"Fruit")
…and so on…
I want to translate this formula into an array formula and put this into the header so the formula will automatically expand.
No matter what I've tried it won't work.
Any help is truly appreciated!
Here's a link to a sheet: [https://docs.google.com/spreadsheets/d/1lgbuLbTSnyKkqr33NdVuDEv5eoXFwatX1rgeF9YpIks/edit?usp=sharing][1]
={"ARRAYFORMULA HERE"; ARRAYFORMULA(IF(LEN(B2:B), IF(B2:B="Fruit",
MMULT(N(ROW(B2:B)>=TRANSPOSE(ROW(B2:B))), N(B2:B="Fruit"))-
HLOOKUP(0, MMULT(N(ROW(B2:B)>TRANSPOSE(ROW(B2:B))), N(B2:B="Fruit")),
MATCH(VLOOKUP(ROW(B2:B), IF(N(B2:B<>B1:B), ROW(B2:B), ), 1, 1),
VLOOKUP(ROW(B2:B), IF(N(B2:B<>B1:B), ROW(B2:B), ), 1, 1), 0), 0), 0), ))}
demo spreadsheet
=ARRAYFORMULA(IF(LEN(B2:B), IF(B2:B="Fruit",
MMULT(N(ROW(B2:B)>=TRANSPOSE(ROW(B2:B))), N(B2:B="Fruit")), 0), ))

Maximum of column 1 where value of column 2 matches some condition

Let's say I have the following in a table :
A | B | desired_output
----------------------------
1 | 10 | 1 | 0
2 | 20 | 7 | 0
3 | 30 | 3 | 0
4 | 20 | 2 | 0
5 | 30 | 5 | 1
I'd like to find a formula for each of the cells in the desired_output column which looks at the max of B1:B5 but only for rows for which A = max(A1:A5)
If that's not clear, I'll try to put it another way :
for all the rows in A1:A5 that are equal to max(A1:A5) // so that's rows 3 and 5
find the one which has the max value on B // so between B3 and B5, that's B5
output 1 for this one, 0 for the other
I'd say there would be a where somewhere if such a function existed, something like = if(B=(max(B1:B5) where A = max(A1:A5)), 1, 0) but I can't find how to do it...
I can do it in two columns with a trick :
A | B | C | D
----------------------------
1 | 10 | 1 | | 0
2 | 20 | 7 | | 0
3 | 30 | 3 | 3 | 0
4 | 20 | 2 | | 0
5 | 30 | 5 | 5 | 1
With Cn = if(An=max(A$1:A$5),Bn,"") and Dn = if(Cn = max(C$1:C$5), 1, 0)
But I still can't find how to do it in one column
For systems without MAXIFS, put this in C1 and fill down.
=--(B1=MAX(INDEX(B$1:B$5-(A$1:A$5<>MAX(A$1:A$5))*1E+99, , )))
=ARRAYFORMULA(IF(LEN(A1:A), IF(IFERROR(VLOOKUP(CONCAT(A1:A&"×", B1:B),
JOIN("×", QUERY(A1:B, "order by A desc, B desc limit 1")), 1, 0), )<>"", 1, 0), ))
or shorter:
=ARRAYFORMULA(IF(A:A<>"",N(A:A&"×"&B:B=JOIN("×",SORTN(A:B,1,,1,0,2,0))),))
=ARRAYFORMULA(IF(A:A<>"",N(A:A&B:B=JOIN(,SORTN(A:B,1,,1,0,2,0))),))
How about the following:
=--AND(A5=MAX($A$1:$A$5),B5=MAXIFS($B$1:$B$5,$A$1:$A$5,MAX($A$1:$A$5)))

googlesheet - Call month API in query statement not work as expected

To summarize each month's balance, I try to call month API in query statement. but sounds like the month API always return (month - 1) but not month.
Example data:
| Type | TransDate | Amount |
|---------+------------+---------|
| Sale | 08/13/2017 | -40.97 |
| Return | 08/10/2017 | 127.48 |
| Payment | 08/07/2017 | 2194.45 |
| Sale | 08/07/2017 | -100.97 |
| Sale | 08/06/2017 | -143.44 |
| Sale | 07/02/2017 | -143.44 |
| Sale | 07/03/2017 | -7.55 |
| Sale | 08/04/2017 | -8.03 |
I use below formula:
=query(A:C,"select MONTH(B),sum(C) where A = 'Sale' or A = 'Return' group by MONTH(B) label MONTH(B) 'Month',sum(C) 'Total'")
The result table:
| Month | Total |
|-------+---------|
| 6 | -150.99 |
| 7 | -165.93 |
The month should be 7 and 8, but actually it return 6 and 7.
As the documentation says:
Returns the zero-based month value from a date or datetime value. For example: month(date "2009-02-05") returns 1. Note: the months are 0-based, so the function returns 0 for January, 1 for February, etc.
As #puts said, the index is start from 0, fix that with a offset:
=query(A:E,"select MONTH(B)+1,sum(E) where A = 'Sale' or A = 'Return' group by MONTH(B) label MONTH(B)+1 'Month',sum(E) 'Total'")

Aerospike: lua udf always returns an empty result even if udf return stream without any filtering, etc

Can not understand why aggregateQuery always returns an empty result. Tried to test in aql, the same problem: 0 rows in set.
Indexes are all there.
aql> show indexes
+---------------+-------------+-----------+------------+-------+------------------------------+-------------+------------+-----------+
| ns | bin | indextype | set | state | indexname | path | sync_state | type |
+---------------+-------------+-----------+------------+-------+------------------------------+-------------+------------+-----------+
| "test" | "name" | "NONE" | "profiles" | "RW" | "inx_test_name" | "name" | "synced" | "STRING" |
| "test" | "age" | "NONE" | "profiles" | "RW" | "inx_test_age" | "age" | "synced" | "NUMERIC" |
aql> select * from test.profiles
+---------+-----+
| name | age |
+---------+-----+
| "Sally" | 19 |
| 20 | |
| 22 | |
| 28 | |
| "Ann" | 22 |
| "Bob" | 22 |
| "Tammy" | 22 |
| "Ricky" | 20 |
| 22 | |
| 19 | |
+---------+-----+
10 rows in set (0.026 secs)
aql> AGGREGATE mystream.avg_age() ON test.profiles WHERE age BETWEEN 20 and 29
0 rows in set (0.004 secs)
It seems that you are trying the example here.
There are two problems about the udf script. I paste the code of the lua script :
function avg_age(stream)
local function female(rec)
return rec.gender == "F"
end
local function name_age(rec)
return map{ name=rec.name, age=rec.age }
end
local function eldest(p1, p2)
if p1.age > p2.age then
return p1
else
return p2
end
end
return stream : filter(female) : map(name_age) : reduce(eldest)
end
First, there is no bin named 'gender' in your set, so you got 0 rows after aggregateQuery.
Second, this script isn't doing exactly what the function name 'avg_age' means, it just return the eldest record with name and age.
I paste my code bellow, it just replace the reduce func, and alert the map and filter func to meat the demand. You can just skip the filter process.
function avg_age(stream)
count = 0
sum = 0
local function female(rec)
return true
end
local function name_age(rec)
return rec.age
end
local function avg(p1, p2)
count = count + 1
sum = sum + p2
return sum / count
end
return stream : filter(female) : map(name_age) : reduce(avg)
end
The output looks like bellow :
AGGREGATE mystream.avg_age() ON test.avgage WHERE age BETWEEN 20 and 29
+---------+
| avg_age |
+---------+
| 22 |
+---------+
1 row in set (0.001 secs)

Truth Table For Switching Functions

Can someone explain how these concept works?
I have 1 question. But I don't know have any ideas on constructing the truth table.
f(A,B,C) = AB + A’C
The answer given was ABC + ABC' + A'BC + A'B'C
And i have no idea how it get there. :-(
1. Create a column for each of the inputs, each intermediate functions, and the final function:
A B C | AB | A' | A'C | AB + A'C
--------------------------------
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
2. Enumerate all input possibilities, and start filling in the intermediate function values and then the final function value:
A B C | AB | A' | A'C | AB + A'C
--------------------------------
0 0 0 | 0 | 1 | 0 | 0
0 0 1 | | | |
0 1 0 | | | |
0 1 1 | | | |
1 0 0 | | | |
1 0 1 | | | |
1 1 0 | | | |
1 1 1 | | | |
3. Now, you finish the truth table.
Update per OP's edit of question:
The "answer given" can be reduced as follows using Boolean Algebra:
ABC + ABC' + A'BC + A'B'C
AB(C + C') + A'C(B + B')
AB + A'C
...which is the same as the given f(A,B,C). Not sure why ABC + ABC' + A'BC + A'B'C would be considered to be the "answer," but this does show equivalence between the two formulae.

Resources