Fetching data in range to process client-side (Google Sheets) - google-apps-script

Using Google Scripts I'm trying to return a string and I get an array.
The code is adapted from another answer: Find Cell Matching Value And Return Rownumber
function updateValues(sheet)
{ // loads named range "CalendarSettings" (on Reserved tab) into array dataSearch for later searching
dataRangeSearch = sheet.getRange("CalendarSettings");
dataSearch = dataRangeSearch.getValues().reduce(function (a, b) {return a.concat(b);});;
}
I was expecting that dataSearch would be a string, since I thought that a.concat(b) would result in a string.
"CalendarSettings" is a named range. Here is a screenshot of what the named range contains.
And here's a screenshot of a msgBox showing the contents of the variable dataSearch.
This looks like an array to me, and it behaves like an array in terms of how it is accessed. But what confuses me is that a.concat(b) I thought would be a string.

Strings and Arrays in JavaScript both have .concat() methods - using .concat() on two arrays will return an array, and on two strings will return a string.
You can turn an array into a string with .toString():
dataSearch = dataRangeSearch.getValues().reduce(function (a, b) {return a.concat(b).toString();});;

Related

Cypress: read, modify and write a json file with a variable as a name of a field

I'm wrapping my head around a function that reads, adds fields and writes JSON back to the file in Cypress:
writeCounterFile(counterName, c) {
const filename = Cypress.env("counterFilePath")
cy.readFile(filename).then((obj) => {
obj.counterName = c
cy.writeFile(filename, obj)
})
return c
}
I'm passing the field name string in counterName argument in the function above trying to get the JSON file content look like:
{
"counter1": NN,
"counter2": XX,
"counter3": YY
}
But the function results in {"counterName": YY} because, aparently, obj.counterName doesn't recognise counterName as the variable.
Plese, help.
There's two ways to add properties to an object, the first with dot notation (.) - as you saw what follows the dot is (literally) the property name.
The second is bracket notation where the property name is given in a variable, this is the one you want
obj[counterName] = c
Ref Property accessors
Syntax
object.property
object['property']

Angular2 IndexOf Finding and Deleting Array Value

Hello I'm attempting delete a certain index in my array while using Angular2 and Typescript. I would like to retrieve the index from the value.
My array is declared normally...
RightList = [
'Fourth property',
'Fifth property',
'Sixth property',
]
I start out with a basic premise to set up my remove function.
removeSel(llist: ListComponent, rlist:ListComponent){
this.selectedllist = llist;
console.log(JSON.stringify(this.selectedllist)); // what is to be searched turned into a string so that it may actually be used
My console.log of my JSON.Stringify tells me that the value that I will attempt to remove is "Sixth property". However when I attempt to look for this value in my array using the following code. It returns -1 which means my value is not found in the array.
var rightDel = this.RightList.indexOf((JSON.stringify(this.selectedllist))); // -1 is not found 1 = found
console.log(rightDel);
On my output to the console it does return the item that is to be searched for but does not find the item in the array
CONSOLE OUTPUT:
"Sixth property" // Item to be searched for
-1 // not found
Is there something wrong in my implementation of my function that searches the array?
Of course indexOf will not find you item in array because
JSON.stringify(this.selectedllist) !== this.selectedllist
This is because JSON stringified string encodes quotes around literal, that original string doesn't have. It is easy to test:
var a = 'test';
console.log( JSON.stringify(a), a, JSON.stringify(a) === a )
Remove JSON.stringify and it should work. In general, to cast something to String type you should use its .toString() method, or simply wrap this something into String(something).

error (Reducer: ) when attempting to do distinct reduce

I am getting an error when trying to do a DISTINCT reduce that I got from here. I have reproduced this error on the beer-sample bucket, so this should be easy to reproduce. I have not seen any errors in the mapreduce_errors.txt file, or anything that would lead me anywhere in the others. (If you would like me to search or post snippets of other files, please ask).
Running couchbase enterprise 4 beta, on Windows 2008 R2 (This also happened on the 3.0.1 community edition as well.).
Here is my map function (Using the beer-sample bucket, that ships directly with couchbase).
function(doc, meta) {
switch(doc.type) {
case "brewery":
emit(meta.id);
break;
}
}
Here is my reduce function:
function(keys, values, rereduce) {
return keys.filter(function (e, i, arr) {
return arr.lastIndexOf(e) === i;
});
}
This is the error:
reason: error (Reducer: )
Also an imgur of the view page if it helps: http://i.imgur.com/KyLutMc.png
The problem lies within your custom reduce function: you're not handling the case when it's being called as part of a re-reduce.
As per Couchbase documentation:
The base format of the reduce() function is as follows:
function(key, values, rereduce) {
...
return retval;
}
The reduce function is supplied three arguments:
key: The key is the unique key derived from the map() function and the
group_level parameter.
values: The values argument is an array of all of the values that match
a particular key. For example, if the same key is output three times,
data will be an array of three items containing, with each item
containing the value output by the emit() function.
rereduce: The rereduce indicates whether the function is being called
as part of a re-reduce, that is, the reduce function being called
again to further reduce the input data.
When rereduce is false:
The supplied key argument will be an array where the first argument is the key as emitted by the map function, and the id is the document ID that generated the key.
The values is an array of values where each element of the array matches the corresponding element within the array of keys.
When rereduce is true:
key will be null.
values will be an array of values as returned by a previous reduce() function. The function should return the reduced version
of the information by calling the return() function. The format of the
return value should match the format required for the specified key.
Bold formatting is mine, and the highlighted words are quite important: you should consider that sometimes, you'll receive the keys argument with a value of null.
According to the docs, you should handle the case when rereduce is true within your reduce() function, and you should know that in this case, keys will be null. In the case of your reduce() function, you could do something like this:
function(keys, values, rereduce) {
if (rereduce) {
var result = [];
for (var i = 0; i < values.length; i++) {
var distinct = values[i];
for (var j = 0; j < distinct.length; j++) {
result.push(distinct[j]);
}
}
return result.filter(function (e, i, arr) {
return arr.lastIndexOf(e) === i;
});
}
return keys.filter(function (e, i, arr) {
return arr.lastIndexOf(e) === i;
});
}
Here, I'm firstly handling the re-reduce phase. For this I'm flattening the array of arrays that I'm receiving in the values argument and then I'm removing the duplicates that might have appeared after the merge.
Then it comes your original code, which returns the keys argument array without duplicates.
To test that this reduce() function actually works, I've used the following map() function:
function(doc, meta) {
switch(doc.type) {
case "brewery":
emit(meta.id, null);
emit(meta.id, null);
break;
}
}
This intentionally generates duplicates, which then are removed by the reduce() function.
While this reduce works as a development view, it does not as a production view. The dataset must be too large so you have to implement the rereduce. This documentation should help http://docs.couchbase.com/admin/admin/Views/views-writing.html#reduce-functions

golang return multiple values issue

I was wondering why this is valid go code:
func FindUserInfo(id string) (Info, bool) {
it, present := all[id]
return it, present
}
but this isn't
func FindUserInfo(id string) (Info, bool) {
return all[id]
}
is there a way to avoid the temporary variables?
To elaborate on my comment, the Effective Go mentions that the multi-value assignment from accessing a map key is called the "comma ok" pattern.
Sometimes you need to distinguish a missing entry from a zero value. Is there an entry for "UTC" or is that the empty string because it's not in the map at all? You can discriminate with a form of multiple assignment.
var seconds int
var ok bool
seconds, ok = timeZone[tz]
For obvious reasons this is called the “comma ok” idiom. In this example, if tz is present, seconds will be set appropriately and ok will be true; if not, seconds will be set to zero and ok will be false.
Playground demonstrating this
We can see that this differs from calling a regular function where the compiler would tell you that something is wrong:
package main
import "fmt"
func multiValueReturn() (int, int) {
return 0, 0
}
func main() {
fmt.Println(multiValueReturn)
asgn1, _ := multiValueReturn()
asgn2 := multiValueReturn()
}
On the playground this will output
# command-line-arguments
/tmp/sandbox592492597/main.go:14: multiple-value multiValueReturn() in single-value context
This gives us a hint that it may be something the compiler is doing. Searching the source code for "commaOk" gives us a few places to look, including types.unpack
At the time of writing this it this the method's godoc reads:
// unpack takes a getter get and a number of operands n. If n == 1, unpack
// calls the incoming getter for the first operand. If that operand is
// invalid, unpack returns (nil, 0, false). Otherwise, if that operand is a
// function call, or a comma-ok expression and allowCommaOk is set, the result
// is a new getter and operand count providing access to the function results,
// or comma-ok values, respectively. The third result value reports if it
// is indeed the comma-ok case. In all other cases, the incoming getter and
// operand count are returned unchanged, and the third result value is false.
//
// In other words, if there's exactly one operand that - after type-checking
// by calling get - stands for multiple operands, the resulting getter provides
// access to those operands instead.
//
// If the returned getter is called at most once for a given operand index i
// (including i == 0), that operand is guaranteed to cause only one call of
// the incoming getter with that i.
//
The key bits of this being that this method appears to determine whether or not something is actually a "comma ok" case.
Digging into that method tells us that it will check to see if the mode of the operands is indexing a map or if the mode is set to commaok (where this is defined does give us many hints on when it's used, but searching the source for assignments to commaok we can see it's used when getting a value from a channel and type assertions). Remember the bolded bit for later!
if x0.mode == mapindex || x0.mode == commaok {
// comma-ok value
if allowCommaOk {
a := [2]Type{x0.typ, Typ[UntypedBool]}
return func(x *operand, i int) {
x.mode = value
x.expr = x0.expr
x.typ = a[i]
}, 2, true
}
x0.mode = value
}
allowCommaOk is a parameter to the function. Checking out where unpack is called in that file we can see that all callers pass false as an argument. Searching the rest of the repository leads us to assignments.go in the Checker.initVars() method.
l := len(lhs)
get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
Since it seems that we can only use the "comma ok" pattern to get two return values when doing a multi-value assignment this seems like the right place to look! In the above code the length of the left hand side is checked, and when unpack is called the allowCommaOk parameter is the result of l == 2 && !returnPos.IsValid(). The !returnPos.IsValid() is somewhat confusing here as that would mean that the position has no file or line information associated with it, but we'll just ignore that.
Further down in that method we've got:
var x operand
if commaOk {
var a [2]Type
for i := range a {
get(&x, i)
a[i] = check.initVar(lhs[i], &x, returnPos.IsValid())
}
check.recordCommaOkTypes(rhs[0], a)
return
}
So what does all of this tell us?
Since the unpack method takes an allowCommaOk parameter that's hardcoded to false everywhere except in assignment.go's Checker.initVars() method, we can probably assume that you will only ever get two values when doing an assignment and have two variables on the left-hand side.
The unpack method will determine whether or not you actually do get an ok value in return by checking if you are indexing a slice, grabbing a value from a channel, or doing a type assertion
Since you can only get the ok value when doing an assignment it looks like in your specific case you will always need to use variables
You may save a couple of key strokes by using named returns:
func FindUserInfo(id string) (i Info, ok bool) {
i, ok = all[id]
return
}
But apart from that, I don't think what you want is possible.
Simply put: the reason why your second example isn't valid Go code is because the language specification says so. ;)
Indexing a map only yields a secondary value in an assignment to two variables. Return statement is not an assignment.
An index expression on a map a of type map[K]V used in an assignment or initialization of the special form
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
yields an additional untyped boolean value. The value of ok is true if the key x is present in the map, and false otherwise.
Furthermore, indexing a map is not a "single call to a multi-valued function", which is one of the three ways to return values from a function (the second one, the other two not being relevant here):
There are three ways to return values from a function with a result type:
The return value or values may be explicitly listed in the "return" statement. Each expression must be single-valued and assignable to the corresponding element of the function's result type.
The expression list in the "return" statement may be a single call to a multi-valued function. The effect is as if each value returned from that function were assigned to a temporary variable with the type of the respective value, followed by a "return" statement listing these variables, at which point the rules of the previous case apply.
The expression list may be empty if the function's result type specifies names for its result parameters. The result parameters act as ordinary local variables and the function may assign values to them as necessary. The "return" statement returns the values of these variables.
As for your actual question: the only way to avoid temporary variables would be using non-temporary variables, but usually that would be quite unwise - and probably not much of an optimization even when safe.
So, why doesn't the language specification allow this kind of special use of map indexing (or type assertion or channel receive, both of which can also utilize the "comma ok" idiom) in return statements? That's a good question. My guess: to keep the language specification simple.
I'm no Go expert but I believe you are getting compile time error when you are trying to return the array i.e. return all[id]. The reason could be because the functions return type is specially mentioned as (Info, bool) and when you are doing return all[id] it can't map the return type of all[id] to (Info, bool).
However the solution mentioned above, the variables being returned i and ok are the same that are mentioned in the return type of the function (i Info, ok bool) and hence the compiler knows what it's returning as opposed to just doing (i Info, ok bool).
By default, maps in golang return a single value when accessing a key
https://blog.golang.org/go-maps-in-action
Hence, return all[id] won't compile for a function that expects 2 return values.

AS3 Custom string formula parser

My goal is to create some kind of Parser to parse string formulas, similar to Excel formulas.
Formula string example (barcode example) -
"CONCAT('98', ZEROFILL([productNumber],5,'0'), ZEROFILL(EQUATION([weightKG]*1000),5,'0'))"
where
'98' - String
[productNumber] and [weightKG] - are variables that can be changed
CONCAT, ZEROFILL and EQUATION are methods which exist in class
For this formula with variables [productNumber] = '1' and [weightKG] = 0.1 result must be
'980000100100'
The question is how to split/parse whole string to parts and detect methods, variables and string values?
Another idea occurred, while i was typing - is to store whole formula in XML format.
Thank You.
You can use String.split() to get an array of substrings.
However, using your example, calling split(",") would give you the following array:
[0]=CONCAT('98'
[1]= ZEROFILL([productNumber]
[2]=5
[3]='0')
[4]= ZEROFILL(EQUATION([weightKG]*1000)
[5]=5
[6]='0'))
That doesn't seem like it will be very helpful for your project. Instead, you might think about creating a parse() function with some logic to find useful substrings:
function parse(input:String):Array {
var firstParen:int = input.indexOf("(");
var lastParen:int = input.lastIndexOf(")");
var formulaName:String = input.substring(0, firstParen);
var arguments:String = input.substring(firstParen, lastParen);
var argumentList:Array = parseArgs(arguments);
var result:Array = new Array();
result.push(formulaName);
//Recursively call parse() on the argumentList
foreach (var elem:* in argumentList) {
result.push(elem); //Could be string or array.
}
}
function parseArgs(input:String):Array {
// Look for commas that aren't enclosed inside parenthesis and
// construct an array of substrings based on that.
//A regex may be helpful here, but the implementation is left
//as an exercise for the reader.
}