I have two arrays:
brands_followed = {'gucci', 'prada'}
brands_unfollowed = {'prada'}
I'm looking to keep only the elements in brands_followed that don't occur in brands_unfollowed - i.e. remove the intersection:
final_brand_selection = {'gucci'}
I see array_intersection() will tell me the elements in both. (But actually brands_unfollowed is a subset of brands followed so it's not useful.) How do I remove the unfollowed brands?
You could use a Javascript UDF for this:
CREATE OR REPLACE FUNCTION array_final(a array, b array)
RETURNS array
LANGUAGE JAVASCRIPT
AS
$$
var c = [];
for (var i = 0; i < A.length; i++){
if (B.includes(A[i]))
continue
else
c.push(A[i])
}
return c
$$;
Then a select:
select array_final(PARSE_JSON('["gucci","prada"]'), PARSE_JSON('["prada"]'));
would give me something like this:
Related
I have some values stored in an Array and now I want to remove ALL the values stored in this array from a filter.
The values are stored correctly in the array but I don't manage to remove the values from the filter.
The Array's name is HideValues
Here is some code:
var p = 0;
spreadsheet.getSheetByName('TEM Tool Data').getRange('\'TEM Tool Data\'!E1').activate();
var criteria = SpreadsheetApp.newFilterCriteria();
//Remove all PID´s from the filter
while (p < HideValues.length){
criteria.setHiddenValues([HideValues[p]]).build();
p++;}
//Filter
spreadsheet.getSheetByName('TEM Tool Data').getFilter().setColumnFilterCriteria(5, criteria);
//Copy filtered area
spreadsheet.getRange('A2:I1386').activate();
//Paste
spreadsheet.getSheetByName('Visualization').getRange('A5').activate();
spreadsheet.getRange('\'TEM Tool Data\'!A2:I1386').copyTo(SpreadsheetApp.getActiveRange(),
SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
spreadsheet.getSheetByName('Visualization').getRange('J3').activate();
};
You don't need to loop through the array
If your array is something like var HideValues = [1,2,3,4,5];,
you can simply specify criteria.setHiddenValues(HideValues).build(); - without the while loop
Also:
To a filter, you should create it first (if not already done) and apply it to a range, not sheet:
var filter = spreadsheet.getSheetByName('TEM Tool Data').getDataRange().createFilter();
filter.setColumnFilterCriteria(3, criteria);
You should apply it to a range, not a sheet
I'm working on a form where I need to pull the contents of a spreadsheet column like 50 times, to try to input multiple items from a list. I see that I can do this by defining a few variables and redoing a small piece of Script again and again. I want to see if anyone can help me overcome this lengthy script to make it smaller with fewer iterations. Thanks.
function updateForm(){
// call the form and connect to the drop-down items
var Form_SQ = FormApp.openById("FORM ID");
var SQ_IT01_List = Form_SQ.getItemById("ITEM 01").asListItem();
var SQ_IT02_List = Form_SQ.getItemById("ITEM 02").asListItem();
//Similarly defining upto 50 dropdown lists.
var SS01 = SpreadsheetApp.getActive();
var SQ_IT01_Names = SS01.getSheetByName("Sheet2");
var SQ_IT02_Names = SS01.getSheetByName("Sheet2");
//Similarly defining upto 50 names lists.
// Item_01 Part Number Dropdown
var SQ_IT01_Values = SQ_IT01_Names.getRange(2, 1, SQ_IT01_Names.getMaxRows() - 1).getValues();
var SQ_IT01_Items = [];
for(var i = 0; i < SQ_IT01_Values.length; i++)
if(SQ_IT01_Values[i][0] != "")
SQ_IT01_Items[i] = SQ_IT01_Values[i][0];
SQ_IT01_List.setChoiceValues(SQ_IT01_Items);
// Item_02 Part Number Dropdown
var SQ_IT02_Values = SQ_IT01_Names.getRange(2, 1, SQ_IT02_Names.getMaxRows() - 1).getValues();
var SQ_IT02_Items = [];
for(var i = 0; i < SQ_IT02_Values.length; i++)
if(SQ_IT02_Values[i][0] != "")
SQ_IT02_Items[i] = SQ_IT02_Values[i][0];
SQ_IT02_List.setChoiceValues(SQ_IT02_Items);
//Similarly defining upto 50 lookup lists.
}
Problem
Reusing code and making use of loops. Scripting is all about efficiency (see DRY principle): make as little assignments and same-functionality coding as possible - use loops, move reusable code snippets to functions that can be called on demand, etc.
Solution
This sample makes several assumptions:
SQ_IT01_Names is different for each item (in your sample it always is Sheet2 - if this is the case, you don't have to reassign it 50 times, one variable assignment will do just fine).
You intended to do something when a value is an empty string (the sample just filters them out). As you use the [index] notation, those values in the resulting Array will be undefined (and that's not something one would want in an Array of choice values).
All items are choice items (if you need id filtering, the sample is easily expanded).
function updateForm() {
var form = FormApp.openById("FORM ID");
//access every item;
var items = form.getItems();
var ss = SpreadsheetApp.getActive();
//loop over items;
items.forEach(function(item,i){
var namesSheet = ss.getSheetByName('Sheet'+i); //assuming this is diff each time;
var namesRange = namesSheet.getRange(2,1,namesSheet.getLastRow());
var namesValues = namesRange.getValues();
//map values to first column;
namesValues = namesValues.map(function(value){
return value[0];
});
//filter out undefined (undefined and false functional equivalence);
namesValues = namesValues.filter(function(value){
return value;
});
item.asListItem().setChoiceValues(namesValues);
});
}
Notes
Please, use closures {} with loops and if statements, this way you'll be able to keep track of which statements are enclosed in it and save yourself debugging time when looping / conditioning multiple statements.
Since you only need rows that have data in them, use the getLastRow() method instead of the getMaxRows()-1 calc you have to perform in your script.
Reference
forEach() method reference;
filter() method reference;
map() method reference;
getLastRow() method reference;
Let's say I have an array of strings and I want to get a list with objects that match, such as:
var locales=Locale.getAvailableLocales()
val filtered = locales.filter { l-> l.language=="en" }
except, instead of a single value I want to compare it with another list, like:
val lang = listOf("en", "fr", "es")
How do I do that? I'm looking for a one-liner solution without any loops. Thanks!
Like this
var locales = Locale.getAvailableLocales()
val filtered = locales.filter { l -> lang.contains(l.language)}
As pointed out in comments, you can skip naming the parameter to the lambda, and use it keyword to have either of the following:
val filtered1 = locales.filter{ lang.contains(it.language) }
val filtered2 = locales.filter{ it.language in lang }
Just remember to have a suitable data structure for the languages, so that the contains() method has low time complexity like a Set.
I have a Google spreadsheet that I'm trying to remove the word "woo" within a range of cells
So far I've managed to loop through the results and log the results, however I haven't figured how to update that information in the spreadsheet itself.
Any guidance would be welcomed
Thank you
function myFunction () {
var ss = SpreadsheetApp.getActiveSheet().getRange('B:B')
var data = ss.getValues();
for (var i = 0; i < data.length; i++) {
var text = data[i].toString();
var finaltext = text.replace(/woo/g, "");
data[i] = finaltext;
Logger.log(data[i]);
}
}
Use setValues()
Notes:
Usually ss is used as a shorthand for spreadsheet, as it's used on the code for a range it's better to use range as a variable name.
setValues() returns a 2D array, so data[i] returns an array of row values rather than a cell value. To get/set cell values, use data[i][0] notation.
Considering the above replace
var ss = SpreadsheetApp.getActiveSheet().getRange('B:B')
by
var range = SpreadsheetApp.getActiveSheet().getRange('B:B')
then add the following line after the for block.
range.setValues(data);
Regarding text var declaration, replace
var text = data[i].toString();
to
var text = data[i][0].toString();
Using open ended references like B:B could lead to problems. To avoid them be sure to keep the sheet rows at minimum or better instead of using an open ended reference use something like B1:B10.
I have an array loaded in, and been playing around in the REPL but can't seem to get this to work.
My array looks like this:
record_id|string|FALSE|1|
offer_id|decimal|FALSE|1|1,1
decision_id|decimal|FALSE|1|1,1
offer_type_cd|integer|FALSE|1|1,1
promo_id|decimal|FALSE|1|1,1
pymt_method_type_cd|decimal|FALSE|1|1,1
cs_result_id|decimal|FALSE|1|1,1
cs_result_usage_type_cd|decimal|FALSE|1|1,1
rate_index_type_cd|decimal|FALSE|1|1,1
sub_product_id|decimal|FALSE|1|1,1
campaign_id|decimal|FALSE|1|1,1
When I run my command:
for(i <- 0 until schema.length){
val convert = schema(i).toString;
convert.split('|').drop(2);
println(convert);
}
It won't drop anything. It also is not splitting it on the |
Strings are immutable, and so split and drop don't mutate the string - they return a new one.
You need to capture the result in a new val
val split = convert.split('|').drop(2);
println(split.mkString(" "));
Consider also defining a lambda function for mapping each item in the array, where intermediate results are passed on with the function,
val res = schema.map(s => s.toString.split('|').drop(2))