I am creating a Google App Script and inside I am trying to create a table structure where the cell data is the value of the row heading + the value of the column heading.
I have the following Headings that represent the day and hour...
var tableHeadings = ["M", "T", "W", "TH", "F", "S", "SU"]
var tableHours = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
I want the contents to be equal to "M0", "M1", "M2", ..., "TH1", ..., etc. So the number of columns is 7 and the number of rows is 10.
I was doing some research into how to do this and found Array Comprehensions, but I quickly found out that those are now NOT supported and we should not use them.
var table = [for (day of tableHeadings) [for (hour of tableHours) day + hour]];
FYI, I don't know if I need to swap the 2 for-clauses yet. I am representing the columns as the days of the week. Also, I don't know if this works on m x n arrays as Google App Script does not allow for this syntax, but if you scroll down to Array comprehensions with two arrays to see an example I used as inspiration.
In most of the documentation, I have been able to find how to convert a single-array Array Comprehension to use maps and filter, but I have not found anything on how to convert a double-array (m x n) Array Comprehension. Some documentation talks about double-array (m x m) Array Comprehension but does not discuss how to convert them.
Is there a simple way to convert a double-array (m x n) Array Comprehension? Just to be very specific, the solution NEEDS to work for (m x n) arrays.
You can achieve this with nested Array#map calls:
var tableHeadings = ["M", "T", "W", "TH", "F", "S", "SU"];
var tableHours = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
var result = tableHeadings.map(function(day) {
return tableHours.map(function(hours) {
return day + hours;
});
});
console.log(result);
And using ES6 arrow functions you can have a one liner:
const tableHeadings = ["M", "T", "W", "TH", "F", "S", "SU"];
const tableHours = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
const result = tableHeadings.map((day) => tableHours.map((hours) => day + hours));
console.log(result);
Related
I have a problem where i must take an array of strings(some numbers and some letters)and remove the Zeros, move them to the end, and return the array. The final result needs all of the numbers to be integers in the string.
I have tried mapping the array and parsing the integers. This works unless the array passed in has letters. then all the letters are relaced with NaN. I cant seem to set up a conditional that will only operate on the integers.
var final = ["a","b","c","d","1","1","3","1","9","9",0,0,0,0,0,0,0,0,0,0];
but it should be
var final = ["a","b","c","d",1,1,3,1,9,9,0,0,0,0,0,0,0,0,0,0]
I need to parse the integers but cant get map to do it without the problem i described earlier. I also tried using if statements too, with no help.
You could convert all numbers or try to convert and take the value, if the conversion is falsy.
var final = ["a", "b", "c", "d", "1", "1", "3", "1", "9", "9", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
console.log(final.map(v => +v || v));
Zero safe approach.
var final = ["a", "b", "c", "d", "1", "1", "3", "1", "9", "9", "0", 0, 0, 0, 0, 0, 0, 0, 0, 0];
console.log(final.map(v => isNaN(v) ? v : +v));
You can try with isNaN() and Array.prototype.map() along with Conditional (ternary) operator:
var final = ["a","b","c","d","1","1","3","1","9","9",0,0,0,0,0,0,0,0,0,0];
final = final.map(i => isNaN(i) ? i : Number(i));
console.log(final);
You want to parse the number but return the original element if it's NaN using a conditional:
var final = array.map((x) => {
var n = parseInt(x, 10);
return !isNaN(n) ? x : n;
})
You could use this:
var input = ["0", "a", "0", "b", "0", "0", "c", "d", "0", 0, "0", "1", "0", "1","3","0", "1","9","9", "0"];
var final = [...input.filter(s => s != 0),
...input.filter(s => s == 0)
].map(s => isNaN(s) ? s : +s);
console.log(final);
Using map() and validating on isNaN().
["a","b","c","d","1","1","3","1","9","9",0,0,0,0,0,0,0,0,0,0]
.map(x => !isNaN(x) ? Number(x) : x)
I have built an ngram model implementation in Javascript, which works fine. However, I am looking to change my data structure so that I do not have to iterate through all the history each time a new word/character is observed.
Here, I take a seedtext and use it to build ngrams with an order 2.
var ngrams = {};
var order = 2;
var seedtext = "adadwsdawdsadawdsadadasdwdadaaasdsadsdadwdasdasd";
build();
function build(){
for (var i = 0; i < seedtext.length - order; i++) {
var gram = seedtext.substring(i, i + order);
var next = seedtext.charAt(i + order);
if (!ngrams.hasOwnProperty(gram)) {
ngrams[gram] = [];
}
ngrams[gram].push(next);
}
}
console.log(ngrams);
console.log(ngrams["wd"]);
I am looking to have a data structure that holds a record of each observed pattern (for a given order. Each observed pattern should have a next possible observation and its count.
For example, if you run the below code, an output such as this can be seen:
[object Object] {
aa: ["a", "s"],
ad: ["a", "w", "a", "a", "a", "a", "s", "w"],
as: ["d", "d", "d", "d"],
aw: ["d", "d"],
da: ["d", "w", "w", "d", "s", "d", "a", "d", "s", "s"],
ds: ["a", "a", "a", "d"],
dw: ["s", "d", "d"],
sa: ["d", "d", "d"],
sd: ["a", "w", "s", "a", "a"],
wd: ["s", "s", "a", "a"],
ws: ["d"]
}
["s", "s", "a", "a"]
Now, if we take "ad" for example: ngrams["ad"], we get back ["a", "w", "a", "a", "a", "a", "s", "w"].
Clearly, after ad we can either get a w,a or s.
I'd like to group the letters so that ngrams["ad"] returns something like:
{a: 5
w: 2
s :1}
Note that they are in order so that the most frequently occurring letter is at the top, with its count.
I'd like to be able to access the data like so (for example):
ngrams["ad"].a;
ngrams["ad"].w;
ngrams["ad"].s;
and get back 5 for a, 2 for w and 1 for s.
I also want to be able to increment the values as a previously seen pattern is observed again... I also want to be able to remove patterns.
Any ideas?
Here is a working version. Instead of an array, you add another object to store counts of next characters in it.
var ngrams = {};
var order = 2;
var seedtext = "adadwsdawdsadawdsadadasdwdadaaasdsadsdadwdasdasd";
build();
function build(){
for (var i = 0; i < seedtext.length - order; i++) {
var gram = seedtext.substring(i, i + order);
var next = seedtext.charAt(i + order);
if (!ngrams.hasOwnProperty(gram)) {
ngrams[gram] = {};
}
if (!ngrams[gram].hasOwnProperty(next)) {
ngrams[gram][next] = 0;
}
ngrams[gram][next] += 1;
}
}
console.log(ngrams);
console.log(ngrams["wd"]);
While trying to get all permutations using Heap's algorithm, I met trouble storing the results in array.
The result generated is (from console.log(arr);)
["1", "2", "3"]
["2", "1", "3"]
["3", "1", "2"]
["1", "3", "2"]
["2", "3", "1"]
["3", "2", "1"]
but only the last value is stored in the arr, and the array stored somehow is this (from console.log(JSON.stringify(allPermutations)); )
["3", "2", "1"]
["3", "2", "1"]
["3", "2", "1"]
["3", "2", "1"]
["3", "2", "1"]
["3", "2", "1"]
var allPermutations = [];
function swap(arr,index1,index2){
var dummy = arr[index1];
arr[index1] = arr[index2];
arr[index2] = dummy;
return arr;
}
function generate(n,arr){
if(n==1){
console.log(arr);
//result:
//["1", "2", "3"]
//["2", "1", "3"]
//["3", "1", "2"]
//["1", "3", "2"]
//["2", "3", "1"]
//["3", "2", "1"]
allPermutations.push(arr);
}else{
for(var i=0;i<n-1;i++){
generate(n-1,arr);
if( n%2 ==0){
arr = swap(arr,i,n-1);
}else{
arr = swap(arr,0,n-1);
}
}
generate(n - 1, arr);
}
}
generate(3,['1','2','3']);
console.log(JSON.stringify(allPermutations));
/*result:
["3","2","1"]
["3","2","1"]
["3","2","1"]
["3","2","1"]
["3","2","1"]
["3","2","1"]*/
What's wrong with this? Would love to understand. Thanks
Replace allPermutations.push(arr) with allPermutations.push(arr.slice()).
The problem is, you keep pushing the same array, then changing that array. When you push an array, you don't push a copy of it: you push a reference. There is only one array, and six references to it; when you read them out, they all read the same, because they are all the same array.
.slice() will give you a new array with the same elements; this way, you get six new arrays into your result, instead of six mentions of the same array.
From one of my earlier answers that is almost-but-not-quite a duplicate, a metaphor I like for this:
As a metaphor, imagine a theatre director in casting. He turns to an actor, says "You... you'll be Romeo.". Then he looks at the same actor, says "You... you'll be Mercutio. Here, Mercutio, take this sword. Romeo... who told you to get a sword?!?" completely failing to realise that, if Romeo and Mercutio are the same person, if one of them picks up a sword, the other does it too.
That's because arrays are objects, and objects are passed by value, but that value is a reference.
Then, your code keeps pushing the same arr reference to allPermutations. But the values in that reference are modified later.
Instead, you should push a copy of the array. You can copy it with .slice().
var allPermutations = [];
function swap(arr, index1, index2) {
var dummy = arr[index1];
arr[index1] = arr[index2];
arr[index2] = dummy;
return arr;
}
function generate(n, arr) {
if (n == 1) {
allPermutations.push(arr.slice());
} else {
for (var i = 0; i < n - 1; i++) {
generate(n - 1, arr);
if (n % 2 == 0) {
arr = swap(arr, i, n - 1);
} else {
arr = swap(arr, 0, n - 1);
}
}
generate(n - 1, arr);
}
}
generate(3, ['1', '2', '3']);
document.write(JSON.stringify(allPermutations));
I have a Google form that gets submitted to a Google spreadsheet. On the spreadsheet side, I have a Google Apps Script that is supposed to encrypt the submitted password. But for whatever reason, it writes an empty string to where the encrypted password should be. This is really starting to stress my out. Here is my code:
function encryptPassword(e) {
var password = e.values[6];
var split = password.split("");
password = "";
var char;
for(char in split) {
password = password.concat(getBinary(split[char]));
}
var spreadsheet = SpreadsheetApp.openById("1CywforbyBmPDHt2Uw9lJtyhqeklAAJp0IG7GfVV6U5U");
spreadsheet.getRange("G" + spreadsheet.getLastRow().toString()).setValue(password);
spreadsheet.getRange("H" + spreadsheet.getLastRow().toString()).setValue(password);
}
function getBinary(char) {
var binary = "";
var numValue;
var range;
var value;
var chars = [
["#", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P"],
["#", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"],
["&", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p"],
["%", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"],
["$", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
];
for(range in chars) {
for(value in range) {
if(value > 0) {
if(char == chars[range][value]) {
numValue = value - 1;
binary = binary + chars[range][0];
if(numValue / 8 >= 1) {
numValue = numValue - 8;
binary = binary.concat("1");
} else {
binary = binary.concat("0");
}
if(numValue / 4 >= 1) {
numValue = numValue - 4;
binary = binary.concat("1");
} else {
binary = binary.concat("0");
}
if(numValue / 2 >= 1) {
numValue = numValue - 2;
binary = binary.concat("1");
} else {
binary = binary.concat("0");
}
if(numValue / 1 >= 1) {
binary = binary.concat("1");
} else {
binary = binary.concat("0");
}
}
}
}
}
return binary;
}
The encryptPassword(e) function is set to run whenever a form is submitted to the spreadsheet. Also please be aware that I have modified the contents of the chars array in an attempt to keep my encryption private. This shouldn't make a difference though since the rest of the code stays the same.
How do I fix my script so it actually writes an encrypted password to the spreadsheet rather than an empty string?
You've got two For/In loops:
for(range in chars) {
for(value in range) {
A For/In loop is meant to loop through the properties of an object. When you use it to loop through an array, like you are doing, the "property" is the index number of the array.
So the line:
for(range in chars) {
Is causing the variable range to be a number value on every loop. On the first loop, the value of range is zero.
The second loop:
for(value in range) {
is never looping. There is nothing to loop through. The value of the variable range is just a single number. You can't loop through a single number. If you use the debugger, you can watch what every line is doing, and execute one line of code at a time.
If you want to get the index position of one of the characters in the password, you could use indexOf(). For example, if the character in the password was the letter "i".
var indexPosition = chars[2].indexOf(char);
The value of indexPosition would be 9. The third array in the outer array chars has an element "i" in the 9th index position.
Let's say that i got a variable which it contains the number 19. I want to make an array from it with the following numbers
var positions = [ "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19" ];
How is this possible in javascript?
Something like :
var number = 19;
var arr = [];
for ( i = 0; i <= number ; i++ ) {
arr.push(i < 10 ? ("0" + i.toString()) : i.toString());
}
demo : http://jsfiddle.net/Kfnnr/1/
Alternatively:
var mynumber = 19,
myarr = String(Array(mynumber+1))
.split(',')
.map(function(el,i){return i<10 ? '0'+i : ''+i;});
For zeropadding you may want to use:
function padLeft(nr,base,chr){
base = base || 10;
chr = chr || '0';
var len = (String(base).length - String(nr).length)+1;
return len > 0? Array(len).join(chr)+nr : nr;
}
// usage
padLeft(1); //=> '01'
padLeft(1,100); //=> '001'
padLeft(1,10000,'-'); //=> '----1'
Update 2019: in es20xx String.prototype contains a native padStart method:
"1".padStart(2, "0"); //=> "01"
// ^ max length
// ^ fill string (or space if omitted)
essentially you want to pad 0's and the answers here will not suffice and scale when the number is changed.. Probably the better solution would be
function padZero(num, size) {
var s = num+"";
while (s.length < size) s = "0" + s;
return s;
}
Using this example finally solved my own ##iterator function interface issue;
Thanks a lot
var myArray = [];
function getInterval (start, step, end, ommit){
for (start; start <= end; start += step) {
myArray.push( start < 10 ? ("" + start.toString()) : start.toString());
}
}
getInterval(2, 2, 20, 20);
myArray; // __proto__: Array
// (10) ["2", "4", "6", "8", "10", "12", "14", "16", "18", "20"]
myArray[4]; // "10"