I have a data set with multiple columns and rows (including text, numbers, dates etc). I want the following to happen:
Example as below. Below is raw information table.
The query will create 8 Files, one for each employee.
ABC will have 2 files with only one row in each file because his Department is different
Benjamin will have 1 file named Benjamin Finance
Timothy will have one file with BOTH rows named Timothy Marketing
Charlene will have 1 file
Tommy will have 1 file
Jerry will have 1 file
Lucy will have 1 file with BOTH rows
function myFunction() {
// Retrieve values from Spreadsheet.
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); // Please set your sheet name.
var \[, ...values\] = sheet.getDataRange().getValues();
// Create an array.
var csvBalanceArray = [, ...values.reduce((m, r) => m.set(r[0], m.has(r[0]) ? [...m.get(r[0]), r] : [r]), new Map()).values()];
// Create text files.
var folder = DriveApp.getFolderById('###'); // Please set your folder ID.
var files = folder.getFiles();
while (files.hasNext()) files.next().setTrashed(true);
csvBalanceArray.forEach((row, index) => folder.createFile("row" + index + ".txt", row.map(r => r.join(" ")).join("\n")));
}
In your script, in order to achieve your goal, how about the following modification?
var csvBalanceArray = [, ...values.reduce((m, r) => m.set(r[0], m.has(r[0]) ? [...m.get(r[0]), r] : [r]), new Map()).values()];
var csvBalanceArray = [...values.reduce((m, [h1, h2, ...r]) => {
var h = h1 + h2;
var temp = r.map(e => e instanceof Date ? Utilities.formatDate(e, Session.getScriptTimeZone(), "dd/MM/yyyy") : e);
return m.set(h, m.has(h) ? [...m.get(h), temp] : [temp]);
}, new Map()).values()];
When this modified script is used, the 1st 2 columns are removed. And, the date object is converted to dd/MM/yyyy
. And, in this case, the header row is not included.
From your reply of however, ABC should have 2 files created because although in Column 1 he is included twice, but in column 2 he is in Finance in row 1 and in Marketing in last row. So he should have two files.
, I updated the above script.
About your following new question,
I've updated the question to add one small change. When the files are created, can these be named as per Column 1 and 2? For example if a file is created for Benjamin, it should be named Benjamin Finance (and so on for other data sets).
and
So currently, if I run the code, the files created are named row0.txt or row1.txt etc. I would like my files to be named as per Column 1 and 2. For example, the file created for first line in the data table will be named 8124 ABC Finance.txt rather than row0.txt. Similarly, for Timothy, it will be named 8124 TIMOTHY Marketing.txt instead of row3.txt.
In this case, how about the following sample script?
function myFunction() {
// Retrieve values from Spreadsheet.
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet34"); // Please set your sheet name.
var [, ...values] = sheet.getDataRange().getValues();
// Create an array.
var csvBalanceArray = [...values.reduce((m, [h1, h2, ...r]) => {
var h = h1 + h2;
var temp = r.map(e => e instanceof Date ? Utilities.formatDate(e, Session.getScriptTimeZone(), "dd/MM/yyyy") : e);
var name = `${h1} ${h2}`;
return m.set(h, m.has(h) ? { row: [...m.get(h).row, temp], name } : { row: [temp], name });
}, new Map()).values()];
console.log(csvBalanceArray)
// Create text files.
var folder = DriveApp.getFolderById('1sJ9b5arpCX26yVIuOKqaen8Mng8KJOiz'); // Please set your folder ID.
var files = folder.getFiles();
while (files.hasNext()) files.next().setTrashed(true);
csvBalanceArray.forEach(({ row, name }) => folder.createFile(`${name}.txt`, row.map(r => r.join(" ")).join("\n")));
}