I have a google form and I would like to sort it's responses in a separate sheet on google sheets. The results of the form look sort of like this.
Id Job
1 Shelving, Sorting
2 Sorting
1 Cleaning, Shelving
3 Customer Service
2 Shelving, Sorting
which I would like to format into
Id Jobs
1 Cleaning, Shelving, Sorting
2 Shelving, Sorting
3 Customer Service
Is there a formula I can use to accomplish this, noting that it ignores duplicates and groups the different ids? Ordering of the jobs does not matter.
Working example here.
The code is like:
=unique(transpose(split(join(", ",filter(B1:B10,A1:A10=1)),", ")))
where
filter(B1:B10,A1:A10=1) gives you all the B values where A = 1
join(",", filter(...)) joins the list with the ", " separator (e.g. "apple, orange" and "kiwi" becomes "apple, orange, kiwi"
split(join(...)) splits the list into an array (e.g. back to [apple, orange, kiwi]
transpose(split(...)) converts the horizontal list to vertical list
unique(transpose(...)) gives you the unique values (unique() only works with vertical list)
After this, you need to transpose then join the list
Note you must keep the separator consistent (e.g. always "," or ", ")
This is Apps Script code instead of a function. To use it, you will need to use the Tools menu, and open the script editor. Then select the function name from the drop down list, and then click the "Run" button.
To use this code, you need to have a source and a destination sheet. You will need to change the sheet names in the code to your sheet names. In this code, the source sheet is named 'Data'. You will need to change that to the name of your source sheet. In this code, the destination sheet is named 'Output', and is at the bottom of the code. This code gets data starting in row two, and writes the output data starting in row two. I tested it with your values and it works.
function concatCellData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName('Data');
var colOneData = sh.getRange(2, 1, sh.getLastRow()-1, 1).getValues();
var colTwoData = sh.getRange(2, 2, sh.getLastRow()-1, 1).getValues();
var newData = [],
newDataColOne = [],
colOneValue,
existInNewData = false,
colB_One,
colB_Two,
dataPosition,
thisValue,
combinedArrays = [],
arrayTemp = [];
for (var i=0;i<colOneData.length;i+=1) {
colOneValue = colOneData[i][0];
dataPosition = newDataColOne.indexOf(colOneValue);
existInNewData = dataPosition !== -1;
if (!existInNewData) {//If it doesn't exist in the new data, just write the values
newDataColOne.push(colOneValue);
newData.push([colOneValue, colTwoData[i][0]]);
continue;
};
colB_One = [];
colB_Two = [];
combinedArrays = []
arrayTemp = [];
colB_One = colTwoData[i][0].split(",");
colB_Two = newData[dataPosition][1];
colB_Two = colB_Two.split(",");
var combinedArrays = colB_One.concat(colB_Two);
//Get unique values
for (var j=0;j<combinedArrays.length;j+=1) {
thisValue = combinedArrays[j].trim();
if (arrayTemp.indexOf(thisValue) === -1) {
arrayTemp.push(thisValue);
};
};
newData[dataPosition] = [colOneValue, arrayTemp.toString()]; //Overwrite existing data
};
ss.getSheetByName('Output').getRange(2, 1, newData.length, newData[0].length).setValues(newData);
};
Related
CONTEXT
I have a source table with multiple columns (Source B table in example spreadsheet).
On column E we have max one name and on column F we can have from 0 to multiple names separated by a comma.
AIM
When there are values in F, add one row per each name (E,F - the last one can have more than one separated by a comma) and duplicate the common values.
It should keep the rows where there are no values in F.
The final result will have one less column than Source table.
WHAT I'VE TRIED
=ARRAYFORMULA(QUERY(IFERROR(SPLIT(FLATTEN(IF(ISBLANK(E3:F6);;
A3:A6&"♦"&B3:B6&"♦"&C3:C6&"♦"&D3:E6&"♦"&E3:E6&"♦"&G3:G6&"♦"&H3:H6&"♦"&I3:I6&"♦"&J3:J6&"♦"&K3:K6&"♦"&L3:L6)); "♦"));
"where Col3 <> 0"; 0))
Problem
This formula was applied to Source A table (in the example spreadsheet and that's = Source B table but without comma separated values in F), which didn't have more than one value in F at the time, and:
duplicates the common values as expected but it's not showing the values from F. Just duplicates the ones from E.
ads blank row if the source row doesn't have values in F
because in column K only one row has a value, it messes up the final data
doesn't do anything different with or without comma separated values in F
Example spreadsheet
--- EDIT ---
I've found this other post with a script that I also tested on the example sheet. I've reduced the number of columns to ease the test and because I think it's aiming for the last column being the one that is supposed to be splitted, if applicable.
It does split but it repeats the "Main" client on the left column and the splited one on the right, where I would like the outcome to have all clients on the same column.
To give you an idea, you can try the following script, I used the "Source for Script" Sheet and created another sheet called "Result". As you can see in the script, I used arrays to collect the data, then added it to the "Result" Sheet.
function splitNewRow() {
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Source for Script");
var data = source.getRange(2, 1, source.getLastRow(), source.getLastColumn()).getValues();
var outcomeSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Result");
newArray = [];
newRow = [];
for (i=0; i < data.length; i++){
var claim = source.getRange(i+2,1).getValue();
var mainClient = source.getRange(i+2,2).getValue();
var others = source.getRange(i+2, 3).getValue();
hasComma = others.indexOf(",") != -1;
if (others != "" && hasComma == true){
newArray = [];
newArray = others.split(",");
newArray.push(mainClient);
for (j=0; j < newArray.length; j++){
newRow = [claim, newArray[j]];
outcomeSheet.appendRow(newRow);
}
}
else if(others != "" && hasComma == false){
newRow = [claim, mainClient];
outcomeSheet.appendRow(newRow);
newRow = [claim, others];
outcomeSheet.appendRow(newRow);
}
else{
newRow = [claim, mainClient];
outcomeSheet.appendRow(newRow);
}
}
}
After running the script, you get the following:
If you have any questions, let me know.
I have a table of tasks where rows are grouped using ID's. I want to represent these groupings in another table where there is one row for each ID and all data rows and columns are grouped for each ID in a single cell. I need a formula that can group certain rows into a cell using newlines, and certain columns into cells using delimiters. My data source is something like this:
The formula needs to:
Filter rows by Condition.
Put Task ID's in their own column, one row for each individual ID.
Put all data in Hours, Mins, Customer and Description columns into a cell next to ID so that:
Hours and Mins are joined with a ":" as a delimiter to represent time values
Customer and Description values are then concatenated to time values using space as a delimiter.
The result should look like:
A Google Sheet containing example of the source table and desired result:
https://docs.google.com/spreadsheets/d/14p_HYpfb7XlWhRRgo3JN7SPRerwEaB2A7Dz1KWuBgL8/edit#gid=299935838
SUGGESTION:
You can try this custom formula GROUPDATA using the script below. Just add it as a bound script on your spreadsheet file:
Script:
function GROUPDATA(data) {
var temp = "";
var filtered = [];
var container = [];
var col2 =[];
var final = [];
data.forEach(function(data) {
if(data[0] == true){
filtered.push(data[1])
container.push([data[1],data[2]+":"+data[3]+" "+data[4]+" "+data[5]])
}
});
const unique = (value,index,self) =>
{return self.indexOf(value) ===index;}
var unique_list=filtered.filter(unique);
for(i=0; i<unique_list.length; i++){
container.forEach(function(x) {
if(x[0]== unique_list[i]){
temp = temp+ x[1]+"\n";
}
});
col2.push(temp);
temp = "";
}
for(y=0; y<unique_list.length; y++){
final.push([unique_list[y],col2[y]]);
}
return final;
}
DEMONSTRATION:
Used the custom formula =GROUPDATA(A:F) on cell G14
need some help with script on google sheets
I'm having some issues to try to use "setVisibleValues" and I got an error saying "Exception: Visible values are not currently supported. As an alternative specify a list of hidden values that excludes the values that should be visible.". But my problem is, I've a huge number of employee names on a list, and I wanna filter just based in one person.
I cant show some information, but the thing is: "I just wanna filter one value, and I don't know how to do it using "setHiddenValues".
function Filtersheet() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A3:S').activate();
spreadsheet.getRange('H3').activate();
var criteria = SpreadsheetApp.newFilterCriteria()
.setHiddenValues([''])
var criteria = SpreadsheetApp.newFilterCriteria()
.setVisibleValues(['tayzer'])
.build();
spreadsheet.getActiveSheet().getFilter().setColumnFilterCriteria(8, criteria);
}
Lets say that the names of the Employees are : jorge, lucas, nuno, fernando, marta, beatriz, tayzer, larissa, and I wanna use the filter script to only show on the column the information related to tayzer
But my way to change the filter employee will be on a cell outside the script (cause I've around 200 employees)
Thanks in advance for the help
try this
function setFilter() {
// replace 'sheet name' with you sheet
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheet name');
var range = ss.getDataRange();
var filter = range.getFilter() || range.createFilter()
var criteria = SpreadsheetApp.newFilterCriteria().whenTextContains('tayzer');
filter.setColumnFilterCriteria(8, criteria);
}
if i am not wrong if you put "jorge" in cell_C4 you want it to filter "jorge" in column E, if so try below code.
function setFilter() {
// replace 'sheet name' with you sheet
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheet name');
var range = ss.getDataRange();
var filter = range.getFilter() || range.createFilter()
var criteria = SpreadsheetApp.newFilterCriteria().whenTextContains(ss.getRange('C4').getValue()).build();
filter.setColumnFilterCriteria(8,criteria)
}
I have a google sheet that I would like to have generate an email alert when one column is greater than the other. Specifically, column F > column G. Here is what I have so far, any advice would be greatly appreciated, as I do not have much skill writing functions.
function readCell() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Watch list");
var value = sheet.getRange("F2").getValue();
var value1 = sheet.getRange("G2").getValue();
if(value>value1) MailApp.sendEmail('example#gmail.com', 'subject', 'message');
};
Currently this only attempts to compare cell F2 to cell G2. Is there a way to make the function compare the entire F column against column G, and generate an email for each individual case where Fx > Gx ?
Thank you!!
You have to loop all over the range.
first instead of getting the content of one cell you'll need to get the content of all the column:
var value = sheet.getRange("F2").getValue();
become that
var values = sheet.getRange("F2:F").getValues();
(same for value1)
then you need to create an empty table that will collect the results:
var results = [];
and now you need to loop throught all the values:
for(var i=0;i<values.length;i++){
//do the comparaison and store result if greater for example
}
then you may send the result.
all put together it give something like that:
function readCell() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Watch list");
var values = sheet.getRange("F2:F").getValues();
var value1s = sheet.getRange("G2:G").getValues();
var results = [];
for(var i=0;i<values.length;i++){
if(values[i]<value1s[i]){
results.push("alert on line: "+(i+2)); // +2 because the loop start at zero and first line is the second one (F2)
}
}
MailApp.sendEmail('example#gmail.com', 'subject', results.join("\n"));
};
If you want to trigger that function automatically you'll also need to change the way you call the spreadsheet (instead of getActive.... you'll need to use openById)
Let I have two column, A and B . How I can find duplicates of this two column combination?
As shown in the picture, duplicate of combination of two column will be colored.
You can get the duplicates highlighted, with the help of following script:
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{name : "Check Duplicates",functionName : "duplicates"}];
sheet.addMenu("Scripts", entries);
};
function duplicates() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Sheet1');
var r = s.getRange("A:B");
var v = r.getValues();
r.setBackground('white');
var f = r.getBackgrounds();
var lastrow = getLastPopulatedRow(v);
for( var i=0;i<lastrow;i++){
for( var j=i+1;j<lastrow;j++){
if( ( v[i][0]==v[j][0] && v[i][1]==v[j][1] ) || ( v[i][0]==v[j][1] && v[i][1]==v[j][0] ) ) {
f[i][0]='lightgreen';
f[i][1]='lightgreen';
f[j][0]='lightgreen';
f[j][1]='lightgreen';
}
}
}
r.setBackgrounds(f);
};
function getLastPopulatedRow(data) {
for (var i=data.length-1;i>=0;i--)
for (var j=0;j<data[0].length;j++)
if (data[i][j]) return i+1;
return 0;
};
Run the function "duplicates" from the script editor. You will also be able to run it from the custom menu "Scripts" from your spreadsheet.
Here is the Screenshot
I think #jwilson gave the proper answer.
However, here is a shortcut method, it may help you.
Select a cell and use CONCATENATE function to join two column value with a space between them. Then you can search the current column if they have duplicates.
For example, using your example image, select your column C1 and add =CONCATENATE(A1," ",B1) and drag this to applicable the formula for all cells in column C. Then add a conditional format rules for column C to check duplicates using =countif(C:C,C1)>1.
Here what is happening is, value of column A and B is concatenating first, then compared if those have duplicate entry in the record.
Use the following Custom formula for Conditional formatting:
=countif(arrayformula($A:$A&"|"&$B:$B);$A1&"|"&$B1)>1