I am using a google forms to collect responses which I will then use to score people. Unfortunately some of those responses only make sense in a non numeric form, here is an example:
Q: What is your most common mode of transportation?
Car
Carpool
Public transportation
Bike
Walk
I want to be able to have google sheets automatically convert those string responses into a number, as in Car will be 20, carpool 15 and so on so that I can "grade" them and give them a score. Can this be done through google forms? Or maybe some sort of dictionary function?
Thank you!
Another method, requiring no coding, would be to make a worksheet with the encoding of the options and then use VLOOKUP to translate them.
Yep, this can be done through Google Forms. Have a look at https://developers.google.com/apps-script/reference/forms/duration-item#setPoints(Integer)
Using their code, you could go something like
var formResponses = FormApp.getActiveForm().getResponses();
// Go through each form response
for (var i = 0; i < formResponses.length; i++) {
var response = formResponses[i];
var items = FormApp.getActiveForm().getItems();
// Assume it's the first item
var item = items[0];
var itemResponse = response.getGradableResponseForItem(item);
if (itemResponse != null && itemResponse.getResponse() == 'Car') {
var points = item.asMultipleChoiceItem().getPoints();
itemResponse.setScore(points * 20);
// This saves the grade, but does not submit to Forms yet.
response.withItemGrade(itemResponse);
}
}
// Grades are actually submitted to Forms here.
FormApp.getActiveForm().submitGrades(formResponses);
Related
Trying to copy a range and paste only formulas, formatting, and data validation (no values) at the end of my sheet so I can enter new values in the freshly pasted range. All is working except I can't figure out how to exclude values when pasting.
Here is my code:
function addCue() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
// copy the first cue range as template
var copyCueRange = ss.getRange("A10:AA11");
// Find the end of the sheet and set pasteRange to match copyRange
var l = ss.getDataRange().getValues().length;
var pasteCueRange = ss.getRange( "A"+(l+1)+":AA"+(l+2) );
// This pastes all data, How do I paste without values?
copyCueRange.copyTo(pasteCueRange);
};
I am very new to coding and appreciate the help. Thank you.
Data Validation: the Range class has a couple of methods for getting and setting data validation rules, setDataValidations() and getDataValidations().
Formulas: just as data validation, Range also has get/set methods for formulas, setFormulas() and getFormulas().
Formatting: looks like the Range.copyTo() method has some options specified here. Try using the formatOnly additional parameter.
function addCue() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
// copy the first cue range as template
var copyCueRange = ss.getRange("A10:AA11");
// Find the end of the sheet and set pasteRange to match copyRange
var l = ss.getDataRange().getValues().length;
var pasteCueRange = ss.getRange( "A"+(l+1)+":AA"+(l+2) );
//Getting data validation and formulas
var dataValidationRules = copyCueRange.getDataValidations();
var formulas = copyCueRange.getFormulas()
//Setting formatting, data validations, and formulas
copyCueRange.copyTo(pasteCueRange, {formatOnly:true});
pasteCueRange.setDataValidations(dataValidationRules);
pasteCueRange.setFormulas(formulas);
}
In a Google Sheet I have a first tab with data entries in column A. I would like to assign a category to each entry in column B using an arrayformula. The category is supposed to be determined in the following way: If in the second tab one of the strings of a column matches the entry, the header of the column is supposed to be assigned as the category.
I have the feeling that there should be a way to do this with the query function, but can't figure it out.
This is an example sheet. I am happy to slightly change the setup of the sheet if the solution requires it but would like to avoid blowing up the sheet. Also I am interested in the simplest possible solution.
Approach
I would use a custom function in this case so that you can gain more control on the logic and structure of your sheet.
First you should change move the categories sheet into a rows structure since Google Sheets gets the values in that way.
Now let's build the function that extracts the data from the categories and assign every name to the corresponding one.
This is a custom function so I build the proper docs header so that it will be visible in your Spreadsheet context.
/**
* Assign the name the corresponding category.
*
* #param {input} the name to assign to the category
* #return The matching category
* #customfunction
*/
function MATCHCATEGORY(input) {
// if the input is from ARRAYFORMULA I will reiterate along the array with a map
if (input.map) {
return input.map(MATCHCATEGORY)
} else {
// Recursion base case
// I will get the categories rows
var rows = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CATEGORIES").getDataRange().getValues();
var category = "";
// Now I will map a string matching function along the rows
rows.map(row => {
let no_blanks = row.filter(value => value != "");
for (var i=1; i<no_blanks.length; i++) {
if (input.includes(row[i])) {
category = row[0];
break;
}
}
});
// Finally I return the category
return category
}
}
Now we can use our custom function inside an ARRAYFORMULA:
=ARRAYFORMULA(MATCHCATEGORY("ENTRY COLUMN RANGE"))
Using Google Scripts, I have a program that retrieves the text from one account's tweets and uses it for various other things. It's been running for over a year with minimal issues, but now the tweets are being adjusted to 280 characters and I can't retrieve the second half of the tweet. I have:
function refreshing_v2() {
var service = getTwitterService();
if (service.hasAccess()) {
var url = 'https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=(redacted)&count=1&include_rts=0&exclude_replies=1';
var response = service.fetch(url);
var tweets = JSON.parse(response.getContentText());
for (var i = 0; i < tweets.length; i++) {
//Parse the tweet
var latest = new String(tweets[i].text);
var maxi_id = tweets[i].id;
var startpos = latest.indexOf("1: ");
etc, etc, continues doing stuff with what it's found.
This allows me to get the FIRST half of the text. What's retrieved looks something like "[Content of first half]...(link to tweet)"
How do I get the full text?
You need to add tweet_mode=extended to get the full text in the response. You may need to check the entities you receive to see if it is what you are expecting.
Documentation link - https://developer.twitter.com/en/docs/tweets/tweet-updates
Additionally, you will need to use full_text rather than just text
So:
//Parse the tweet
var latest = new String(tweets[i].full_text);
See the sample tweet at https://github.com/twitterdev/tweet-updates/blob/master/samples/initial/compatibilityplus_extended_13997.json
According to the documentation, it needs to follows the Form Post rules at: https://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4. When looking at that information it did not give me much to work with in terms of complex objects or maps.
Right now, If I have a list for example: Each item in the list needs to be stringified.
var params = {"list": [1,2,3]};
// needs to be stringed.
params["list"] = params["list"].map((item)=>item.toString()).toList();
Simple. Also all base items need to be a string as well
var params = {"number": 1, "boolean": true};
params = params.forEach((k,v)=> params[k].toString());
But how do we handle maps?
var params = {"map": {"a":1,"b":"foo","c":false,"d":[]}};
// ??
It seems that after testing in my app and in dart pad, you need to make sure everything is strings, so i am trying to come up with a way to effectively cover lists, maps, and maybe more complex objects for encoding.
var params = {};
params["list"] = [1,2,3];
params["number"] = 1;
params["boolean"] = true;
params["map"] = {"a":1,"b":"foo","c":false,"d":[]};
params.forEach((String key, dynamic value){
if(value is List){
params[key] = value.map((v)=>v.toString()).toList();
}else if(value is Map){
// ????
}else{
params[key] = value.toString();
}
//maybe have an additional one for custom classes, but if they are being passed around they should already have their own JSON Parsing implementations.
}
Ideally, the result of this would be passed into:
Uri myUri = new Uri(queryParameters: params);
and right now, while i solved the list issue, it doesn't like receiving maps. Part of me just wanted to stringify the map as a whole, but i wasn't not sure if there was a better way. I know that when someone accidentally stringified the array, it was not giving me: ?id=1&id=2 but instead ?id=%5B1%2C2%5D which was not correct.
I don't think there is any special support for maps. Query parameters itself is a map from string to string or string to list-of-strings.
Everything else need to be brought into this format first before you can pass it as query parameter.
A simple approach would be to JSON encode the map and pass the resulting string as a single query parameter.
I am trying to setup a search in umbraco examine.I have two search fields ,material and manufacturer.when I trying to search with one material and one manufactuere it will give the correct result.but when try to search more than one material or manufacturer it doesn't give the result.here is my code
const string materialSearchFields = "material";
const string manufacturerSearchFields = "manufacturer";
if (!string.IsNullOrEmpty(Request.QueryString["material"]))
{
material = Helper.StripTags(Request.QueryString["material"]);
}
if (!string.IsNullOrEmpty(Request.QueryString["manufacturer"]))
{
manufacturer = Helper.StripTags(Request.QueryString["manufacturer"]);
}
if (!string.IsNullOrEmpty(Request.QueryString["material"]) || !string.IsNullOrEmpty(Request.QueryString["manufacturer"]))
{
var query = userFieldSearchCriteria.Field(materialSearchFields, material).And().Field(manufacturerSearchFields, manufacturer).Compile();
contentResults = contentSearcher.Search(query).ToList();
}
here my search keywors in querystring is material=iron,steel
how can we split this keyword and search done?
Thanks in advance for the help....
You are using the AND operator, in your case I think you are looking for the GROUPEDOR instead?
I was just working in an old project and grabbed this snipet from there (which I've adapted for your needs). I think it's going to help you:
public IEnumerable<DynamicNode> SearchUmbraco(string[] keywords, string currentCulture)
{
// In this case I had some diferent cultures, so this sets the BaseSearchProvider to the given culture parameter. You might not need this, use your default one.
BaseSearchProvider searcher = SetBaseSearchProvider(currentCulture);
var searchCriteria = searcher.CreateSearchCriteria(BooleanOperation.Or);
var groupedQuery = searchCriteria.GroupedOr(new[] {"manufacturer", "material"}, keywords).Compile();
var searchResults = searcher.Search(groupedQuery);
// ... return IEnumerable of dynamic nodes (in this snipet case)
}
I just split(etc) the keywords in an helper and pass them to a string array when I call this method.
Just check this infomation on the umbraco blog: http://umbraco.com/follow-us/blog-archive/2011/9/16/examining-examine.aspx