Why is Arrayformula returning only the first row - date

Update: sample sheet provided here: https://docs.google.com/spreadsheets/d/1BapXdaVOUL634SstNJXqYNocsD_EvvtlbJ77vlElmZs/edit?usp=drivesdk. Any help will be appreciated!
Hi fellow nerds.
I'm trying to make the current column (most recent interaction date with client) display the max values (most recent dates) from ContactLog!b:b (dates of all recorded interactions), when the client name in ContactLog!A:A matches to the client name in current row column A.
After many days of trying, I've found several formulas to successfully achieve this result for the current cell only.
=MAXIFS(ContactLog!B:B, ContactLog!A:A, A:A)
=MAX(FILTER(ContactLog!B4:B, ContactLog!A4:A=VLOOKUP(A2, ContactLog!A4:B, 1, FALSE)))
=MAX(QUERY(ContactLog!A4:B, ""SELECT B WHERE A = '""&VLOOKUP(A2, ContactLog!A4:B, 1, FALSE)&""'"", 0))
=IF(COUNTIF(ContactLog!A:A, A2),MAX(FILTER(ContactLog!B:B, ContactLog!A:A = A2)),"")
But none of these seem to work with arrayformula, to spread to the entire column. I'd like this result to apply automatically to the entire column (wherever column A is not blank).
It's displaying the correct max value for the first cell (in which the formula is written), and I could drag the formula down, but not spreading automatically as an array.
I've tried using =match with =filter, but that keeps running into mismatched range row sizes. (I've previously solved that by using filter within a filter, but can't figure that out here).
[I have a similar issue for the nearby columns also, "most recent interaction method", and "reminders & goals". The formula there is:
=INDEX(ContactLog!C:C, MATCH(MAX(IF(ContactLog!A:A=A2, IF(ContactLog!B:B=MAX(IF(ContactLog!A:A=A2, ContactLog!B:B)), ROW(ContactLog!B:B)))), ROW(ContactLog!B:B), 0))
And
=IFERROR(CONCATENATE(JOIN(" • ",FILTER(ContactLog!D:D,ContactLog!A:A=A2, ContactLog!D:D<>"")),IF(INDEX(ContactLog!D:D,MAX(IF(ContactLog!A:A=A2,ROW(ContactLog!D:D))))="","","")),"")
They both work great, but I can't get them to work with arrayformula...]
What am I missing?

You can do something like this with BYROW, that allows you to expand your formula through the column and be calculated "row by row". Using your first option:
=BYROW(A:A, LAMBDA (each,IF(each="","",MAXIFS(ContactLog!B:B, ContactLog!A:A, each))))

Related

Cannot properly array googlefinance formula with dates

I am trying to convert money amounts in USD to EUR, but I want to do it in relation to date of transaction taking place due to dyncamic exchange rates.
Idea is to use googlefinance function with index function, along with date function, which will be made of right, mid, and left functions. All of that should be wrapped with arrayformula. Numbers should be rounded using round.
Non-working example:
Don't mind ;, this is instead of , in my google sheets language settings.
Formula: =ARRAYFORMULA(IF(B2:B="";"";ROUND(INDEX(B2:B*GOOGLEFINANCE("CURRENCY:USDEUR";"price";DATE(RIGHT(A2:A;4);MID(A2:A;4;2);LEFT(A2:A;2)));2;2);2)))
Formula (with , instead of ;):
=ARRAYFORMULA(IF(B2:B="","",ROUND(INDEX(B2:B*GOOGLEFINANCE("CURRENCY:USDEUR","price",DATE(RIGHT(A2:A,4),MID(A2:A,4,2),LEFT(A2:A,2))),2,2),2)))
Since I'm pretty sure this formula should work in "normal circumstances", I've replicated it leaving out arrayformula, and full ranges (such as B2:B, etc), and it works once I drag down the formula.
Working example:
Formula: =IF(F2="";"";ROUND(INDEX(F2*GOOGLEFINANCE("CURRENCY:USDEUR";"price";DATE(RIGHT(E2;4);MID(E2;4;2);LEFT(E2;2)));2;2);2))
Formula (with , instead of ;):
=IF(F2="","",ROUND(INDEX(F2*GOOGLEFINANCE("CURRENCY:USDEUR","price",DATE(RIGHT(E2,4),MID(E2,4,2),LEFT(E2,2))),2,2),2))
Does anyone have idea what's going on with the first case, i.e. why it doesn't work? I believe it has to be something with those full ranges (e.g. B2:B, A2:B, etc), but not sure why...
GOOGLEFINANCE is already an ARRAYFORMULA type formula so try like this:
=ARRAYFORMULA(IF(B2:B="";;ROUND(B2:B*IFNA(VLOOKUP(A2:A+0,9986111111;
GOOGLEFINANCE("CURRENCY:USDEUR"; "price"; MIN(A2:A); MAX(A2:A)+1); 2; 1)); 2)))

Set new column definition by setColumnDefs doesn't work anymore

I'm trying to set new column definitions by calling setColumnDefs using the grid API. This doesn't work as expected. The names of the column headers will not be updated anymore!
See this Plunkr: Version 19.1.x
Version 19.0.0 is latest working version.
See this Plunkr: Version 19.0.0
For me it seems to be a bug!?
In my project I'm using Angular 5 and I notice the same behaviour.
I was able to reproduce your behaviour. The following (dirty) workaround works:
gridOptions.api.setColumnDefs([]);
gridOptions.api.setColumnDefs(newColDefs);
Setting the columnDefs to an empty array and then passing the newColDefs seems to achieve what you are looking for.
I suppose it up to the new way of change-detection on the latest version.
If you will update your code like that:
function updateColDef()
{
let data = [];
columnDefs.forEach(function(colDef) {
colDef.headerName = colDef.headerName + ' X ';
data.push(colDef);
})
data.push( {
headerName: 'New Column',
});
gridOptions.api.setColumnDefs(data);
}
It will work as expected.
Update:
When new columns are set, the grid will compare with current columns and work out which columns are old (to be removed), new (new columns created) or kept (columns that remain will keep their state including position, filter and sort).
Comparison of column definitions is done on 1) object reference comparison and 2) column ID eg colDef.colId. If either the object reference matches, or the column ID matches, then the grid treats the columns as the same column.
In the first case, it was an object comparison, on the second sample (after update) its colId case.
changes came from 19.1 version release
AG-1591 Allow Delta Changes to Column Definitions.

Conditionally selecting the most recent occurrence of a variable?

I have a variable called "Effort", a variable called ID, and ID2. One ID has many ID2's. So I want to know when hovering over a bar chart what the most recent Effort was per ID.
Here are the two attempts I have made which did not work:
LOOKUP(ATTR([Effort]), Last() + 0)
IF(LAST([Effort])) == 0 THEN([Effort]) END
I was leaning towards the first one working, but it didn't seem to do what I was requiring correctly.
Any guidance would be greatly appreciated!

Having issues with a substring function in Tableau

I am trying to break a string up into substrings based on the position of a repeating set of characters.
The source string [UPDATES] looks like this, the number of characters between the repeating portions varies wildly.
"04/24/15 15:12:54 (PZPJ3F): Task update. 04/24/15 15:12:54 (PZPJ3F): Task update. 04/22/15 15:17:13 (SZGQ3T): updated due date prior to global problem 04/22/15 12:28:09 (PZPJ3F): Task updates."
I am trying to break them up into separate substrings so that I can display them side by side as separate columns as below
Column1 = |04/24/15 15:12:54 (PZPJ3F): Task update.
Column2 = |04/24/15 15:12:54 (PZPJ3F): Task update.
Column3 = |04/22/15 15:17:13 (SZGQ3T): updated due date prior to global problem|
I got the first portion to work with
LEFT([UPDATES],FIND([UPDATES],"): ",28)-27)
But my attempts at using FIND to locate the next occurrence of "): " and use it to begin a MID are not working, specifically where I try to end them using a FIND function.
IF [Mark1]>0 THEN MID([UPDATES],[Mark1]-25,[Mark2])
ELSE ""
END
Where Mark1 is
FLOAT(FIND([UPDATES],"): ",(FIND([UPDATES],"): ")+1)))
and Mark2 is
FLOAT(FIND([UPDATES],") ",[Mark1]+1))
I really went down the rabbit hole at the end of my attempt.
I am using Tableau 8.2, so Tableau 9 functions aren't an option (looking forward to FIND Nth!
Thanks in advance.
The key is that find() takes a second optional argument as a start position.
So in Tableau 8.2, I would write a simple calc to find the position of the first separator. Then reference that calculated field twice in your final calculated fields to yield the length of the first substring and the starting point of the second one.
Separating out substrings is painful prior to Tableau 9. Extracting the first in a list isn't bad, getting the second is clumsy and after that it gets pretty ugly.
Best approach is to upgrade to version 9 or do some preprocessing to pull out the substrings.

dataFrame keying using pandas groupby method

I new to pandas and trying to learn how to work with it. Im having a problem when trying to use an example I saw in one of wes videos and notebooks on my data. I have a csv file that looks like this:
filePath,vp,score
E:\Audio\7168965711_5601_4.wav,Cust_9709495726,-2
E:\Audio\7168965711_5601_4.wav,Cust_9708568031,-80
E:\Audio\7168965711_5601_4.wav,Cust_9702445777,-2
E:\Audio\7168965711_5601_4.wav,Cust_7023544759,-35
E:\Audio\7168965711_5601_4.wav,Cust_9702229339,-77
E:\Audio\7168965711_5601_4.wav,Cust_9513243289,25
E:\Audio\7168965711_5601_4.wav,Cust_2102513187,18
E:\Audio\7168965711_5601_4.wav,Cust_6625625104,-56
E:\Audio\7168965711_5601_4.wav,Cust_6073165338,-40
E:\Audio\7168965711_5601_4.wav,Cust_5105831247,-30
E:\Audio\7168965711_5601_4.wav,Cust_9513082770,-55
E:\Audio\7168965711_5601_4.wav,Cust_5753907026,-79
E:\Audio\7168965711_5601_4.wav,Cust_7403410322,11
E:\Audio\7168965711_5601_4.wav,Cust_4062144116,-70
I loading it to a data frame and the group it by "filePath" and "vp", the code is:
res = df.groupby(['filePath','vp']).size()
res.index
and the output is:
[E:\Audio\7168965711_5601_4.wav Cust_2102513187,
Cust_4062144116, Cust_5105831247,
Cust_5753907026, Cust_6073165338,
Cust_6625625104, Cust_7023544759,
Cust_7403410322, Cust_9513082770,
Cust_9513243289, Cust_9702229339,
Cust_9702445777, Cust_9708568031,
Cust_9709495726]
Now Im trying to approach the index like a dict, as i saw in examples, but when im doing
res['Cust_4062144116']
I get an error:
KeyError: 'Cust_4062144116'
I do succeed to get a result when im putting the filepath, but as i understand and saw in previouse examples i should be able to use the vp keys as well, isnt is so?
Sorry if its a trivial one, i just cant understand why it is working in one example but not in the other.
Rutger you are not correct. It is possible to "partial" index a multiIndex series. I simply did it the wrong way.
The index first level is the file name (e.g. E:\Audio\7168965711_5601_4.wav above) and the second level is vp. Meaning, for each file name i have multiple vps.
Now, this is correct:
res['E:\Audio\7168965711_5601_4.wav]
and will return:
Cust_2102513187 2
Cust_4062144116 8
....
but trying to index by the inner index (the Cust_ indexes) will fail.
You groupby two columns and therefore get a MultiIndex in return. This means you also have to slice using those to columns, not with a single index value.
Your .size() on the groupby object converts it into a Series. If you force it in a DataFrame you can use the .xs method to slice a single level:
res = pd.DataFrame(df.groupby(['filePath','vp']).size())
res.xs('Cust_4062144116', level=1)
That works. If you want to keep it as a series, boolean indexing can help, something like:
res[res.index.get_level_values(1) == 'Cust_4062144116']
The last option is a bit less readable, but sometimes also more flexibile, you could test for multiple values at once for example:
res[res.index.get_level_values(1).isin(['Cust_4062144116', 'Cust_6073165338'])]