How to create array dynamically from a string without copy pasting? - arrays

I have these as strings: { column01 \ column02 \ column01 }(for other countries { column01 , column02 , column01 }). I want them evaluated as a array as if copy pasted.
The array string range is created automatically, based on the selection of the user. I created a dynamically personalized dataset based on a sheet studeertijden named. The user can easily select the wanted tables by checkboxes, so by Google Sheets ARRAY range (formula). I try to copy these content to an other sheet ... to make the required data available for Google Data Studio.
The contents of page studeertijden is NOT important. Let's say, a cell in 'legende-readme'!B39 returns a string with the required columns/data in a format like this:
{ studeertijden!A:A \ studeertijden!B:B}
If I put this in an empty sheet, by copy and paste, it works fine :
={ studeertijden!A:A \ studeertijden!B:B}
How can it be done automatically???
my first thought was by indirect ...
What I've tried(Does NOT work):
Cell 'legende - readme'!B39 contains:
{ studeertijden!A:A \ studeertijden!B:B}
=indirect('legende - readme'!B39)
returns :
#REF! - It is not a valid cell/range reference.
={ indirect('legende - readme'!B39) }
returns :
#REF! - It is not a valid cell/range reference.
={'legende - readme'!B39}
returns : { studeertijden!A:A \ studeertijden!B:B}
Note : For European users, use a '\' [backslash] as the column separator. Instead of the ',' [comma].

Assuming I've understood the question, if string doesn't need to start and end with curly brackets, then is this the behaviour you are looking for?
=arrayformula(transpose(split(byrow(transpose(split(string,",")),lambda(row,join(",",indirect(row)))),",")))
N.B. In my case I'm assuming that string is of the format 'studeertijden!A:A,studeertijden!B:B' (i.e. comma separated). So SPLIT by the comma to generate a column vector of references, TRANSPOSE to a row vector, INDIRECT each row (with the JOIN to return a single cell per row), ARRAYFORMULA/SPLIT to get back to multiple cells per row, TRANSPOSE back into columns like the original data.
This would be a lot easier if BYROW/BYCOL could return a matrix rather than being limited to just a row/column vector - the outer SPLIT and the JOIN in the BYROW wouldn't be needed. Over in Excel world they can also use arrays of thunks rather than string manipulation to deal with this limitation (which Excel also has), but Google Sheets doesn't seem to allow them when I've tried - see https://www.flexyourdata.com/blog/what-is-a-thunk-in-an-excel-lambda-function/ for more details.

Thanks to Natalia Sharashova of AbleBits, she provided this working solution (for the complete sheet).
referenceString is the reference to the string to all wanted columns; array matrix; { studeertijden!A:A \ studeertijden!B:B}
Note :
for European users, use a ' \ ' - [backslash] as the column separator
instead of the default ' , ' - [comma]
=REDUCE(
FALSE;
ArrayFormula(TRIM(SPLIT(REGEXREPLACE( referenceString ; "^=?{(.*?)}$"; "$1"); "\"; TRUE; TRUE)));
LAMBDA(accumulator; current_value;
IF(
accumulator = FALSE;
INDIRECT(current_value);
{ accumulator \ INDIRECT(current_value)}
)
)
)

={"1" , "2"}
={"1" \ "2"}
both are valid. it all depends on your locale settings
see: https://stackoverflow.com/a/73767720/5632629
with indirect it would be:
=INDIRECT("sheet1!A:B")
where you can build it dynamically for example:
=INDIRECT("sheet1!"& A1 &":"& B1)
where A1 contains a string like A or A1 (and same for B1)
another way how to construct range is with ADDRESS like:
=INDIRECT(ADDRESS(1; 2)
from another sheet it could be:
=INDIRECT(ADDRESS(1; 2;;; "sheet2")
or like:
=INDIRECT("sheet2!"&ADDRESS(1; 2))
for a range we can do:
=INDIRECT("sheet2!"&ADDRESS(1; 2)&":"&ADDRESS(10; 3))

Related

Replacing cell specific seperator in Google Sheets - 21.06.2019 to 21/06/2019

can someone help me in replacing periods with forwarding slashes in sheets?
I have a data set with over 100 thousand rows in sheets,
I have a date-time formatted as such D.M.Y I need to change it to D/M/Y
each row has 7 or so columns based on date-time.
anyways, below is the first 6 rows of column 'A'
so its format is D.M.Y
so I have 100,000 rows of this in column 'A'
Date
21.06.2019
22.06.2019
23.06.2019
24.06.2019
25.06.2019
26.06.2019
I want to turn it into this
Date
21/06/2019
22/06/2019
23/06/2019
24/06/2019
25/06/2019
26/06/2019
I need it in this format as sheet does not recognize the '.' as a separator and it would take an eternity to do it manually, thanks!
A link to my screen below to see the format
check if your dates are valid dates with:
=ISDATE(A2)
if yes use this in B2:
=ARRAYFORMULA(TEXT(A2:A; "dd/mm/yyyy"))
if no you can use:
=ARRAYFORMULA(SUBSTITUTE(A2:A; "."; "/"))
and if you need real dates do:
=ARRAYFORMULA(QUERY(IFERROR(DATEVALUE(SUBSTITUTE(A2:A; "."; "/")));
"format(Col1) 'dd/mm/yyyy'"))
Assuming your data is on Sheet1 in columns A through G.
On a blank tab, say Sheet2, in cell A1, you could use this formula to substitute the . with /.
=ARRAYFORMULA(SUBSTITUTE(Sheet1!A:G,".","/"))
This should give you the substituted values. You could then copy these and paste them as values to Sheet1.
if you want to use macro or script do like this:
function ReplaceDotToSlash()
{
var sheet = SpreadsheetApp.getActive().getSheetByName('YourSheetName');
var lastRow = sheet.getLastRow();
for (var i = 1; i < lastRow+1; i++){
var value1 = sheet.getRange('A'+i).getValue() + "";
sheet.getRange('A'+i).setValue(value1.replace(/\./g, "/"));
}
}

Update dynamically headers of DataTable in Matlab

Is there an efficient way of updating dynamically the headers of a Table after performing T = array2table(P) on a matrix P of dimension e.g.(1x120) rather than manually resorting to T.Properties.VariableNames{i} = xxx for I belonging to [2;120]?
As Matlab assigns by default {Var1,....Var120} on T, the idea is to iterate over each column header of T and assign then a new name = T_Var2,....T_Var120} where T represents the table name
Once unique column headers is performed on T, then outerjoin could be used with other tables (using the expected solution) as they will share a unique key on Var1. A feedback would be very appreciated.
You can define the headers when you call array2table.
Here I first create all of the names (use your desired table name in place of 'Table_Var' and then assign when creating the table.
% Create unique headers, 'Table_Var1', 'Table_Var2', 'Table_Var3', ...
headers = arrayfun( #(x) sprintf('Table_Var%d',x), 1:size(P,2), 'uni', 0 );
% Assign headers when creating the table
T = array2table( P, 'VariableNames', headers );
If you wanted column 1 to always have the same name, say 'Col1', and only columns 2:end to use the table name, you could use:
headers = ['Col1', arrayfun( #(x) sprintf('Table_Var%d',x), 2:size(P,2), 'uni', 0 ) ]
Once you have a cell array of headers, you can also just rename the table variable names in one shot (you don't need to do this if you did it at the array2table stage)
T.Properties.VariableNames = headers;

Concatenate fields of a dynamic structure

How do we concatenate fields of a dynamic work area? The idea is in the below code:
LOOP AT lt_final INTO DATA(ls_final).
CONCATENATE ls_final-field1
ls_final-field2
ls_final-field3
ls_final-field4
ls_final-field5
INTO ls_attachment SEPARATED BY lc_tab. "lc_tab is horizontal tab
APPEND ls_attachment TO lt_attachment.
CLEAR: ls_attachment.
ENDLOOP.
(This code will be used for sending email attachment.) Now, my problem is, the internal table in the above code is a dynamic internal table, therefore I am not sure how many fields will be there and the field names as well.
How do I concatenate the fields? Any idea, please help..
LOOP AT <dynamic_table> INTO DATA(ls_final).
CONCATENATE ls_final-(?)
ls_final-(?)
ls_final-(?)
ls_final-(?)
ls_final-(?)
"or more fields insert here depending on dynamic table
INTO ls_attachment SEPARATED BY lc_tab. "lc_tab is horizontal tab
APPEND ls_attachment TO lt_attachment.
CLEAR: ls_attachment.
ENDLOOP.
FIELD-SYMBOLS: <lv_field> TYPE ANY.
LOOP AT lt_final
ASSIGNING FIELD-SYMBOL(<ls_final>).
DO.
ASSIGN COMPONENT sy-index
OF STRUCTURE <ls_final>
TO <lv_field>.
IF sy-subrc EQ 0.
IF sy-index EQ 1.
ls_attachment = <lv_field>.
ELSE.
ls_attachment = ls_attachment && lc_tab && <lv_field>.
ENDIF.
ELSE.
EXIT.
ENDIF.
ENDDO.
ENDLOOP.
I hope it is self explaining, but:
You can use the system variable (sy-index), it is incremented automatically by SAP.
In the first step, just copy the value, there is nothing to concatenate yet (otherwise there will be an unnecessary lc_tab at the beginning of the string).
Just read your structure by index.
data :
lv_attachment type string.
lv_index type i value 1.
field-symbols:
<lv_value> type any.
while 1 = 1.
assign component lv_index of structure ls_final to <lv_value>.
if sy-subrc <> 0.
exit.
endif.
concatenate lv_attachment <lv_value> into lv_attachment separated by lc_tab.
lv_index = lv_index + 1.
endwhile.
Hope it helps.
You can use CL_ABAP_CONTAINER_UTILITIES class for that task, method FILL_CONTAINER_C.
Here is the sample of populating dynamic table and concatenating its fields into container field:
PARAMETERS: p_tab TYPE string.
FIELD-SYMBOLS: <fs_tab> TYPE STANDARD TABLE.
DATA tab TYPE REF TO data.
CREATE DATA tab TYPE TABLE OF (p_tab).
ASSIGN tab->* TO <fs_tab>.
SELECT * UP TO 100 ROWS
INTO TABLE <fs_tab>
FROM (p_tab).
LOOP AT <fs_tab> ASSIGNING FIELD-SYMBOL(<fs_line>).
CALL METHOD CL_ABAP_CONTAINER_UTILITIES=>FILL_CONTAINER_C
EXPORTING
IM_VALUE = <fs_line>
IMPORTING
EX_CONTAINER = DATA(container)
EXCEPTIONS
ILLEGAL_PARAMETER_TYPE = 1
others = 2.
CONDENSE container.
" do smth
ENDLOOP.

3 part formula for linking string data from different / same cell

A1
Michael Lewis
B1
'at'xyz
I would like an individual formula to do each of the following
Michael.lewis#xyz.com (First Name ‘dot’ Surname)
M.lewis#xyz.com (First initial ‘dot’ Surname)
mlewis#xyz.com (First initialSurname)
Id like a drop down menu to change which formula I am using.
Is this possible?
I'm not sure if I get exactly what you need, but here goes.
I had to translate all the formulas back to english because my work computer is in a different locale but I think it's right (in case there's a typo I missed)
The formulas you asked for in respective order:
(B11 = name, B12 = email domain)
=LEFT(B11;SEARCH(" ";B11)-1) & "." & RIGHT(B11; LEN(B11)-SEARCH(" ";B11))& "#" &B12
=LEFT(B11;1) & "." & RIGHT(B11; LEN(B11)-SEARCH(" ";B11))& "#" &B12
=LEFT(B11;1) & RIGHT(B11; LEN(B11)-SEARCH(" ";B11))& "#" &B12
Then you can just add a data validation list pointing to the cells you write the formulas on and it should work as intended, I hope.
Accessing first name in cell A1:
= LEFT(A1,FIND(" ",A1)-1)
Accessing last name in cell A1:
= RIGHT(A1,FIND(" ",A1)-1)
Accessing first initial in cell A1:
= LEFT(A1,1)
Getting passed the 'at' in cell B1 and only returning xyz:
= RIGHT(B1,5)
Therefore, for example, <first name>.<last name> is:
= LEFT(A1,FIND(" ",A1)-1)&"."&RIGHT(A1,FIND(" ",A1)-1)&"#"&RIGHT(B1,5)&".com"
If you remove the 'at' from cell B1 and just have xyz, then the formula above could be slightly simplified; You can substitute RIGHT(B1,5) simply with B1.
Also, the LOWER function converts all text to lowercase.
For example to get the lowercase first letter of first name, formula would be:
= LOWER(LEFT(A1,1))

MATLAB Extract all rows between two variables with a threshold

I have a cell array called BodyData in MATLAB that has around 139 columns and 3500 odd rows of skeletal tracking data.
I need to extract all rows between two string values (these are timestamps when an event happened) that I have
e.g.
BodyData{}=
Column 1 2 3
'10:15:15.332' 'BASE05' ...
...
'10:17:33:230' 'BASE05' ...
The two timestamps should match a value in the array but might also be within a few ms of those in the array e.g.
TimeStamp1 = '10:15:15.560'
TimeStamp2 = '10:17:33.233'
I have several questions!
How can I return an array for all the data between the two string values plus or minus a small threshold of say .100ms?
Also can I also add another condition to say that all str values in column2 must also be the same, otherwise ignore? For example, only return the timestamps between A and B only if 'BASE02'
Many thanks,
The best approach to the first part of your problem is probably to change from strings to numeric date values. In Matlab this can be done quite painlessly with datenum.
For the second part you can just use logical indexing... this is were you put a condition (i.e. that second columns is BASE02) within the indexing expression.
A self-contained example:
% some example data:
BodyData = {'10:15:15.332', 'BASE05', 'foo';...
'10:15:16.332', 'BASE02', 'bar';...
'10:15:17.332', 'BASE05', 'foo';...
'10:15:18.332', 'BASE02', 'foo';...
'10:15:19.332', 'BASE05', 'bar'};
% create column vector of numeric times, and define start/end times
dateValues = datenum(BodyData(:, 1), 'HH:MM:SS.FFF');
startTime = datenum('10:15:16.100', 'HH:MM:SS.FFF');
endTime = datenum('10:15:18.500', 'HH:MM:SS.FFF');
% select data in range, and where second column is 'BASE02'
BodyData(dateValues > startTime & dateValues < endTime & strcmp(BodyData(:, 2), 'BASE02'), :)
Returns:
ans =
'10:15:16.332' 'BASE02' 'bar'
'10:15:18.332' 'BASE02' 'foo'
References: datenum manual page, matlab help page on logical indexing.

Resources