Remove Duplicate based on 2 columns in Google sheets - javascript

This code removes the duplicate in the column name called "Receipt Number"
How to modify this code if the conditions matches to two column as duplicate. (i.e. Receipt Number Column and Mobile Number Column should be duplicate at the same time)
function removeDuplicates() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName("Records");
var vA=sh.getDataRange().getValues();
var hA=vA[0];
var hObj={};
hA.forEach(function(e,i){hObj[e]=i;});//header title to index
var uA=[];
var d=0;
for(var i=0;i<vA.length;i++) {
if(uA.indexOf(vA[i][hObj['Receipt Number']])==-1) {
uA.push(vA[i][hObj['Receipt Number']]);
}else{
sh.deleteRow(i+1-d++);
}
}
}
Thanks in advance.

I believe your goal is as follows.
You want to remove the duplicated rows by using the condition of 2 columns.
For example, when the columns of Receipt Number and Mobile Number are as follows, you want to delete the following 2 rows (4 and 5).
1 Receipt Number Mobile Number
2 a2 b2
3 a3 b3
4 a2 b2 <--- delete
5 a3 b3 <--- delete
6 a2 b3
7 a3 b2
If my understanding is correct, how about the following modification? In this modification, removeDuplicates is used.
Modified script:
function removeDuplicates() {
var checkHeadeTitles = ["Receipt Number", "Mobile Number"]; // This header titles are from your question.
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName("Records");
var header = sh.getRange(1, 1, 1, sh.getLastColumn()).getValues()[0];
var columnNumber = checkHeadeTitles.map(e => {
var idx = header.indexOf(e);
if (idx == -1) {
throw new Error(`No header tilte of '${e}'.`);
}
return idx + 1;
});
sh.getRange(2, 1, sh.getLastRow() - 1, sh.getLastColumn()).removeDuplicates(columnNumber);
var row = sh.getDataRange().getValues().findIndex(r => r.join("") == "");
if (row == -1) return;
sh.deleteRow(row + 1);
}
When this script is run to the above sample sheet, rows 4 and 5 are deleted.
References:
map()
removeDuplicates(columnsToCompare)

function removeDuplicates() {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName("Records");
var [hA, ...vA] = sh.getDataRange().getValues();
var idx = {};
hA.forEach(function (e, i) { idx[e] = i; });
var uA = [];
var d = 0;
for (var i = 0; i < vA.length; i++) {
let x = `${vA[i][idx['Receipt Number']]}-${vA[i][idx['Receipt Number']]}`
if (!~uA.indexOf(x)) {
uA.push(x);
} else {
sh.deleteRow(i + 2 - d++);
}
}
}

Related

Google Apps Script Filtering

I have some data in google sheet which I want to filter based on a certain criteria and return a corresponding value from another column. Lastly, count the number of elements in the returned column. Here is a sample data:
Sample data
A
B
1
Initials
Application Reference
2
MWB.KBB
1001
3
JET,JJB
1002
4
KBB
100,310,041,005
5
MKGC
1006
6
KBB
1007
Let's say I want to filter the data by searching for "KBB". I want to get all cells that contain the word "KBB" which should be three (3) cells. However, I am only getting two in return. The 1st row that contain two elements in a single cell is not included but it should be included. Lastly, count the elements in the returned column based on the criteria.
Here's the code I have tried:
function filter(){
//opened ss via url
const ws = ss.getSheetByName("Sample");
const range = ws.getRange(2,1,ws.getLastRow() - 1,2).getValues();
const initial = range.map(function(n){return n[0];});
const filtered = initial.filter(filterLogic);
Logger.log(initial); // [MWP, KBB, JET, JJB, KBB, MKGC, KBB]
Logger.log(filtered); // [KBB, KBB]
}
function filterLogic(name){
if(name == "KBB"){
return true;
} else {
return false;
}
}
The above code is only for the criteria. Not included is the counting of elements for the returned value from another column after the filter is applied.
What should I do so I can include the first row that contains the text "KBB" as well in my filtered data. Is there any other way around this?
Code:
function searchForKBB(n = "KBB") {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Sheet0");
const osh = ss.getSheetByName("Sheet1");
let o = sh.getRange(1,1,sh.getLastRow(),sh.getLastColumn()).createTextFinder(n).matchEntireCell(false).findAll().map(rg => [rg.getA1Notation()]);
o.unshift(["Ranges"]);
osh.getRange(1,1,o.length,o[0].length).setValues(o)
}
Data:
A
B
1
Initials
Application Reference
2
MWB.KBB
1001
3
JET,JJB
1002
4
KBB
100,310,041,005
5
MKGC
1006
6
KBB
1007
Results:
Ranges
A2
A4
A6
Maybe you can do this:
```
function getAllKBBs(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ss1 = ss.getSheetByName("YOUR_SHEET_NAME");
var range = ss1.getRange(1,1,ss1.getLastRow(),4).getValues();
output = whenTextContains("KBB", range, 1, 1);
Logger.log(output.length);
} ```
where whenTextContains() function is in this repository
https://github.com/NikolaPlusEqual/GoogleAppsScriptFilters/blob/main/Functions
Or, you can copy this into you code and call above function:
function letterToColumn(letter){
var column = 0, length = letter.length;
for (var i = 0; i < length; i++)
{
column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
}
return column;
}
////// source for letterToColumn() function :
////// https://stackoverflow.com/questions/21229180/convert-column-index-into-corresponding-column-letter
var setData = {}
function whenTextContains(txt, rng, col, targetCol = 0){
if (typeof col == "number" && typeof txt == "string"){
setData.col = col;
setData.txt = txt;
}
else{
return;
}
var output = rng.filter(wtc);
if(targetCol == 0){
return output;
}
else if(typeof targetCol == "number"){
var result = output.map(function (item) {
return item[targetCol-1];
});
return result;
}
else if(typeof targetCol == "string"){
var targetnum = letterToColumn(targetCol);
var result = output.map(function (item) {
return item[targetnum-1];
});
return result;
}
else{
return;
}
}
function wtc(ar){
var txt = setData.txt;
var col = setData.col - 1;
var str = ar[col].toString();
return str.includes(txt);
}

Is there a way to add values to some random cells from a range?

I have the following code:
function test1() {
var app = SpreadsheetApp;
var activesheet = app.getActiveSpreadsheet().getActiveSheet();
for (var j = 2; j<= 3; j++) {
activesheet.getRange(j,2).setValue("C");
}
}
This code will add the character "C" to the cell B2 and B3 which is great.
I am looking to get my code to add two "C" characters to 2 random cells from the first 30 cells of the B column.
Any help is much appreciated. Thank you.
This code may help you
function test1() {
var app = SpreadsheetApp;
var activesheet = app.getActiveSpreadsheet().getActiveSheet();
let randomCellIndex;
let usedCell = [];
for (var i = 0; i < 2; i++) {
// make sure not to use same index twice
do
randomCellIndex = Math.floor(Math.random() * 30) + 1;
while (usedCell.indexOf(randomCellIndex) !== -1);
usedCell.push(randomCellIndex);
activesheet.getRange(randomCellIndex,2).setValue("CC");
}
}
I assume that you don't want duplicate values so i would grab two values from shuffled array. To avoid going into the rabbit hole with shuffling array exsample uses underscore
_.shuffle([...Array(30)].map((value, index) => index+1))
Adds character string to range n times making a unique selection each time.
function addCharsRandom(chr = "AB", a1rg = "", n = 3) {
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();
const rg = (a1rg.length < 2) ? sh.getActiveRange() : sh.getRange(a1rg);
if (rg.getDisplayValues().flat().length >= n) {
rg.setBackground("yellow")
const w = rg.getWidth();
const h = rg.getHeight();
const r = rg.getRow();
const c = rg.getColumn();
let rA = [];
let cA = [];
[...Array.from(new Array(n).keys())].forEach(i => {
let row, col;
do {
row = r + Math.floor(Math.random() * h);
col = c + Math.floor(Math.random() * w);
} while (rA.indexOf(row)>-1 && cA.indexOf(col)>-1);
rA.push(row);
cA.push(col);
sh.getRange(row, col).setValue(sh.getRange(row, col).getDisplayValue() + chr).setBackground("white");
});
} else {
SpreadsheetApp.getUi().alert("Range is to small for number of unique selections");
}
}
if a1rg equals "" then it will select the active range.
Demo:

Insert values in the last row of a determined column with app script

I need to copy the values ​​in the last row of a certain column, I was seeing examples like this... Stackoverflow but they have not served me with my script. The problem I have is that in the column A I have five values and in the column B and C I have only one like this ...
A B C
1 1 1
1 - -
1 - -
1 - -
1 - -
and I want to insert values ​​in the column B andC like this...
A B C
1 1 1
1 2 2
1 2 2
1 - -
1 - -
but the problem with my script is that it inserts them like this...
A B C
1 1 1
1 - -
1 - -
1 - -
1 - -
- 2 2
//This part its not important
function last(){
var ss = SpreadsheetApp.openById("ID");
var ssh = ss.getSheetByName("Name")
var Range = ssh.getRange("B1:C");
var getVal = Range.getValues();
//This part its the important
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssh = ss.getSheetByName("Sheet 1");
var lastRow = ssh.getLastRow() + 1;
var ssRange = ssh.getRange(lastRow , 2, getVal.length, getVal[0].length).setValues(getVal);
}
I need help so that the values ​​are inserted in the correct row.
EDIT
This is the script that I have...
function last(){
var ss = SpreadsheetApp.openById("ID");
var name = ss.getSheetByName("NAMES");
var lastRow = name.getLastRow();
var range = name.getRange("A"+(lastRow)+":D"+(lastRow));
var datas = range.getValues();
var actSs = SpreadsheetApp.getActiveSpreadsheet();
var sheetOne = actSs.getSheetByName("1");
var ltRo = sheetOne.getLastRow();
var startRow = null;
var i = 0;
while(i < datas.length)
{
if(datas[i][0]){
startRow = i + 2;
i++;
}
if (!i){
startRow = 1;
}
var ssRange = sheetOne.getRange(startRow, 2, datas.length,
datas[0].length).setValues(datas);
}
}
and this is the Spreadsheet
Another method I have used previously from this answer:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssh = ss.getSheetByName("Sheet 1");
var Avals = ssh.getRange("B1:B").getValues();
var Alast = Avals.filter(String).length;
var ssRange = ssh.getRange(Alast +1 , 2, getVal.length, getVal[0].length).setValues(getVal);
this is the problem:
var lastRow = ssh.getLastRow() + 1;
your finding the last row with datas in your spreadsheet which is in your case 6.
use getValues() to get the array of data, then parse to find the index where no data is found in column 2.
and do:
var ssRange = ssh.getRange(foundIndex , 2, getVal.length, getVal[0].length).setValues(getVal);
Example:
function last(){
var ss = SpreadsheetApp.openById("ID");
var name = ss.getSheetByName("Name")
var range = name.getRange("B1:C");
var datas = range.getValues();
var actSs = SpreadsheetApp.getActiveSpreadsheet();
var sheetOne = actSs.getSheetByName("Sheet 1");
var startRow = null;
var i = 0;
while(i < datas.length)
{
if(datas[i][0])
startRow = i + 2;
i++;
}
if (!i)
startRow = 1;
var ssRange = sheetOne.getRange(startRow , 2, datas.length, datas[0].length).setValues(datas);

Split column on first delimiter and output before and after delimiter gs script

Very new to this
cell data looks like:
colx
aa, bbb
oue, hed, ono
hud
need it to become:
colx coly colz
aa, bbb aa bbb
oue, hed, ono oue hed, ono
hud hud
I am needing to split a column on its first delimiter then post back the first part (everything before the first delimiter)in the next column to the right of the original column and post back the rest of the string (everything after the first delimiter) to the 2nd column to the right of the original column
I found the function SplitTheString here:
How do I split a string, breaking at a particular character?
I know my code does not work cant get how to fix it, in particular how to output the data
Thanks
function splitColumn() {
var range =getColRng("Elements","colx", 2)
var values = range.getValues());
for (var row in values[0]) {
values[row][0] == SplitTheString(ResultStr);)
}
range.setValues(values);
}
Helper Functions:
function SplitTheString(ResultStr) {
if (ResultStr != null) {
var SplitChars = ', ';
if (ResultStr.indexOf(SplitChars) >= 0) {
var DtlStr = ResultStr.split(SplitChars);
var name = DtlStr[0];
var street = DtlStr[1];
}
}
}
function getColRng(shtName, cheader,startrow) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(shtName);
var lc = sheet.getMaxColumns();
var lr = sheet.getLastRow();
var hn = HTN(shtName,cheader)
return sheet.getRange(startrow, hn, lr);
}
How about the following sample script? This script supposes that there are data in the column A.
Sample script :
function splitColumn() {
var ss = SpreadsheetApp.getActiveSheet()
var range = ss.getRange(1, 1, ss.getLastRow(), 1);
var values = range.getValues();
var result = [];
for (var i in values) {
if (i == 0) {
result.push([values[i][0], "coly", "colz"]);
} else {
var splitted = values[i][0].split(",");
var others = splitted.slice(1, splitted.length).join(",");
result.push([values[i][0], splitted[0], others]);
}
}
ss.getRange(ss.getLastRow()+1, 1, result.length, result[0].length).setValues(result);
}
Input :
Output :
If I misunderstand your question, please tell me. I would like to modify.
Edit :
function splitColumn() {
var ss = SpreadsheetApp.getActiveSheet();
var range = ss.getRange(2, 1, ss.getLastRow(), 1);
var values = range.getValues();
var result = [];
for (var i in values) {
if (values[i][0]) {
var splitted = values[i][0].split(",");
var others = splitted.slice(1, splitted.length).join(",");
result.push([splitted[0], others]);
} else {
result.push(["",""]);
}
}
ss.getRange(2, 2, result.length, result[0].length).setValues(result);
}

Delete blank rows in spreadsheet using Google script

Spreadsheet-1: Data present in Spreadsheet-1,
Name apple android windows linux
Germany 3 4 6 7
America 4 1 6 2
Sweden 1 6 1 6
Paris 5 0 2 4
Spreadsheet-2: Data present in Spreadsheet-2,
Date Name apple android windows linux
I am able to copy the data from spreadsheet1 to spreadsheet2 by using the below google script.
function Daily() {
var SpreadSheetKeyA = "mykey1";
var SpreadSheetKeyB = "mykey2";
var sheet1 = SpreadsheetApp.openById(SpreadSheetKeyA).getSheetByName("Showstopper");
var sheet2 = SpreadsheetApp.openById(SpreadSheetKeyB).getSheetByName("Daily");
var data = sheet1.getRange(5,11,40,6).getValues();
var time = new Date ().toJSON().slice(0,10);;
for (var r = 0; r < data.length; r++) {
data[r].unshift(time);
sheet2.appendRow(data[r]);
}
}
The data present in spreadsheet1 is dynamic i.e, the number of rows can vary. Now whenever I run the script again so as to update the spreadsheet2 data is being appended after blank rows. I would like enhance the above script so that it should avoid blank rows or only copy rows with data.
Can anyone help me with this please
This should work if all blanks are at the bottom of the source and there is nothing else below the data.
function triggerOnTime() {
var SpreadSheetKeyA = "MY key";
var SpreadSheetKeyB = "MY key";
var sheet1 = SpreadsheetApp.openById(SpreadSheetKeyA).getSheetByName("Source Name");
var sheet2 = SpreadsheetApp.openById(SpreadSheetKeyB).getSheetByName("Target Name");
var startRow = 5;
var data = sheet1.getRange(startRow,11,sheet1.getLastRow() - startRow + 1,5).getValues();
var time = new Date ().toJSON().slice(0,10);;
for (var r = 0; r < data.length; r++) {
data[r].unshift(time);
}
if(data.length > 0 ) {
sheet2.insertRowsAfter(sheet2.getLastRow(), data.length);
sheet2.getRange(sheet2.getLastRow()+1, 1, data.length, data[0].length).setValues(data);
}
}
If for whatever reason the above conditions cannot be met and you need to hardcode the number of rows to 40 you might try the following:
function triggerOnTime() {
var SpreadSheetKeyA = "MY key";
var SpreadSheetKeyB = "MY key";
var sheet1 = SpreadsheetApp.openById(SpreadSheetKeyA).getSheetByName("Source Name");
var sheet2 = SpreadsheetApp.openById(SpreadSheetKeyB).getSheetByName("Target Name");
var startRow = 5;
var data = sheet1.getRange(5,11,40,6).getValues();
var time = new Date ().toJSON().slice(0,10);;
for(var i = data.length - 1; i > -1; i--) {
if(data[i].join("").length == 0) data.splice(i, 1);
}
for (var r = 0; r < data.length; r++) {
data[r].unshift(time);
}
if(data.length > 0 ) {
sheet2.insertRowsAfter(sheet2.getLastRow(), data.length);
sheet2.getRange(sheet2.getLastRow()+1, 1, data.length, data[0].length).setValues(data);
}
}

Categories

Resources