1
11
12
1121
122111
112213
122211
....
I was trying to solve this problem. It goes like this.
I need to check the former line and write: the number and how many time it was repeated.
ex. 1 -> 1(number)1(time)
var antsArr = [[1]];
var n = 10;
for (var row = 1; row < n; row++) {
var lastCheckedNumber = 0;
var count = 1;
antsArr[row] = [];
for (var col = 0; col < antsArr[row-1].length; col++) {
if (lastCheckedNumber == 0) {
lastCheckedNumber = 1;
antsArr[row].push(lastCheckedNumber);
} else {
if (antsArr[row-1][col] == lastCheckedNumber) {
count++;
} else {
lastCheckedNumber = antsArr[row-1][col];
}
}
}
antsArr[row].push(count);
antsArr[row].push(lastCheckedNumber);
}
for (var i = 0; i < antsArr.length; i++) {
console.log(antsArr[i]);
}
I have been on this since 2 days ago.
It it so hard to solve by myself. I know it is really basic code to you guys.
But still if someone who has a really warm heart help me out, I will be so happy! :>
Try this:
JSFiddle Sample
function lookAndSay(seq){
var prev = seq[0];
var freq = 0;
var output = [];
seq.forEach(function(s){
if (s==prev){
freq++;
}
else{
output.push(prev);
output.push(freq);
prev = s;
freq = 1;
}
});
output.push(prev);
output.push(freq);
console.log(output);
return output;
}
// Sample: try on the first 11 sequences
var seq = [1];
for (var n=0; n<11; n++){
seq = lookAndSay(seq);
}
Quick explanation
The input sequence is a simple array containing all numbers in the sequence. The function iterates through the element in the sequence, count the frequency of the current occurring number. When it encounters a new number, it pushes the previously occurring number along with the frequency to the output.
Keep the iteration goes until it reaches the end, make sure the last occurring number and the frequency are added to the output and that's it.
I am not sure if this is right,as i didnt know about this sequence before.Please check and let me know if it works.
var hh=0;
function ls(j,j1)
{
var l1=j.length;
var fer=j.split('');
var str='';
var counter=1;
for(var t=0;t<fer.length;t++)
{
if(fer[t]==fer[t+1])
{
counter++;
}
else
{
str=str+""+""+fer[t]+counter;
counter=1;
}
}
console.log(str);
while(hh<5) //REPLACE THE NUMBER HERE TO CHANGE NUMBER OF COUNTS!
{
hh++;
//console.log(hh);
ls(str);
}
}
ls("1");
You can check out the working solution for in this fiddle here
You can solve this by splitting your logic into different modules.
So primarily you have 2 tasks -
For a give sequence of numbers(say [1,1,2]), you need to find the frequency distribution - something like - [1,2,2,1] which is the main logic.
Keep generating new distribution lists until a given number(say n).
So split them into 2 different functions and test them independently.
For task 1, code would look something like this -
/*
This takes an input [1,1,2] and return is freq - [1,2,2,1]
*/
function find_num_freq(arr){
var freq_list = [];
var val = arr[0];
var freq = 1;
for(i=1; i<arr.length; i++){
var curr_val = arr[i];
if(curr_val === val){
freq += 1;
}else{
//Add the values to the freq_list
freq_list.push([val, freq]);
val = curr_val;
freq = 1;
}
}
freq_list.push([val, freq]);
return freq_list;
}
For task 2, it keeps calling the above function for each line of results.
It's code would look something like this -
function look_n_say(n){
//Starting number
var seed = 1;
var antsArr = [[seed]];
for(var i = 0; i < n; i++){
var content = antsArr[i];
var freq_list = find_num_freq(content);
//freq_list give an array of [[ele, freq],[ele,freq]...]
//Flatten so that it's of the form - [ele,freq,ele,freq]
var freq_list_flat = flatten_list(freq_list);
antsArr.push(freq_list_flat);
}
return antsArr;
}
/**
This is used for flattening a list.
Eg - [[1],[1,1],[1,2]] => [1,1,1,1,2]
basically removes only first level nesting
**/
function flatten_list(li){
var flat_li = [];
li.forEach(
function(val){
for(ind in val){
flat_li.push(val[ind]);
}
}
);
return flat_li;
}
The output of this for the first 10 n values -
OUTPUT
n = 1:
[[1],[1,1]]
n = 2:
[[1],[1,1],[1,2]]
n = 3:
[[1],[1,1],[1,2],[1,1,2,1]]
n = 4:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1]]
n = 5:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3]]
n = 6:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3],[1,2,2,2,1,1,3,1]]
n = 7:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3],[1,2,2,2,1,1,3,1],[1,1,2,3,1,2,3,1,1,1]]
n = 8:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3],[1,2,2,2,1,1,3,1],[1,1,2,3,1,2,3,1,1,1],[1,2,2,1,3,1,1,1,2,1,3,1,1,3]]
n = 9:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3],[1,2,2,2,1,1,3,1],[1,1,2,3,1,2,3,1,1,1],[1,2,2,1,3,1,1,1,2,1,3,1,1,3],[1,1,2,2,1,1,3,1,1,3,2,1,1,1,3,1,1,2,3,1]]
I have a column of cells in a particular sheet of Google Spreadsheet document.
This column references multiple values in another sheet using the built-in JOIN command:
=JOIN(", ",Regular!B3,Regular!B9,Regular!B10,Regular!B11,Regular!B12,Regular!B13,Regular!B14)
typical output for each such cell is a list of integers that are comma-separated, f.ex:
2, 5, 10, 12, 13
Some cells use ranges like this:
=JOIN(", ",Regular!B3:B9)
I want to lock these cells in the formula as such: Regular!$B$3,Regular!$B:$9...
Right now I want each reference to lock both column and row, but a solution that lets me pick row, column or both is a better solution.
1) I haven't found a way to do this without using a custom script - have I missed something?
2) My custom script solution is unfinished:
function eachCellInRange(range, op) {
var numRows = range.getNumRows();
var numCols = range.getNumColumns();
for (var i = 1; i <= numRows; i++) {
for (var j = 1; j <= numCols; j++) {
op(range.getCell(i,j), i, j);
}
}
};
function lockCell(cell, row, col) {
var formula = cell.getFormula();
if(formula) {
var startIdx = formula.indexOf('(');
if(startIdx > 0) {
//!! REGEX HERE !! //
cell.setValue(formula);
}
}
}
function lockRows() {
var range = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getActiveRange();
eachCellInRange(range, lockCell);
};
I need to make a regex pattern that will identify the B3, B9... parts of the formula and change them to $B$3, $B$9... but also not break in the B1:B8 case
Currently all references are prefixed with SheetName! (e.g. Regular!B9:B20), in the future some may not be, so the most general solution is preferred.
I'm not sure whether this is what you're looking for but I would replace the little bit you currently have:
if(formula) {
var startIdx = formula.indexOf('(');
if(startIdx > 0) {
//!! REGEX HERE !! //
cell.setValue(formula);
}
}
by
if(formula.substring(0,6) == "=JOIN(") {
formula = formula.replace(/([A-Z]+(?=[0-9]))/g, function($1) {
return "$" +$1 + "$";
});
alert(formula);
// cell.setValue(formula);
}
Which ensures that the formula is a JOIN formula.
Also, I'm not that familiar with JS, but I put it in JSFiddle to see how it goes.
Warning: This will fail if your sheet names have alphanumeric characters (mix of letters and digits).
Using #Jerry's useful answer, I was able to suit it to my needs:
function eachCellInRange(range, op) {
var numRows = range.getNumRows();
var numCols = range.getNumColumns();
for (var i = 1; i <= numRows; i++) {
for (var j = 1; j <= numCols; j++) {
op(range.getCell(i,j), i, j);
}
}
};
var lockOn = 1, lockOff = -1, lockNop = 0,
lockChar = '$', lockEmpty = '';
function lock2char(newLock, curLock) {
if(newLock == lockNop) newLock = curLock;
return (newLock > lockNop) ? lockChar : lockEmpty;
}
function bool2lock(boolValue) {
return (boolValue) ? lockOn : lockOff;
}
function lockCell(lockCol, lockRow, cell, row, col) {
var formula = cell.getFormula();
if(formula) {
var startIdx = formula.indexOf('(');
if(startIdx > 0) {
var newFormula = formula.replace(/([A-Z|\$]+(?=[0-9]))/g, function(part) {
var prefix = lock2char(lockCol, (part.charAt(0) == lockChar));
var suffix = lock2char(lockRow, (part.charAt(part.length -1) == lockChar));
part = part.replace(/\$/g, '');
return prefix + part + suffix;
});
cell.setFormula(newFormula);
}
}
}
function lockRows() {
var range = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getActiveRange();
eachCellInRange(range, lockCell.bind(this, lockOff, lockOn));
};
I am trying to grab a certain value. I am new to javascript and I can't figure out why this is not working.
If I parse "kid_2" I should get "kostas". Instead of "Kostas" I always get "02-23-2000". So I must have a logic problem in the loop but I am really stuck.
function getold_val(fieldname,str){
var chunks=str.split("||");
var allchunks = chunks.length-1;
for(k=0;k<allchunks;k++){
var n=str.indexOf(fieldname);
alert(chunks[k]);
if(n>0){
var chunkd=chunks[k].split("::");
alert(chunkd);
return chunkd[1];
}
}
}
var test = getold_val('kid_2','date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||');
alert(test);
A regex may be a little more appealing. Here's a fiddle:
function getValue(source, key){
return (new RegExp("(^|\\|)" + key + "::([^$\\|]+)", "i").exec(source) || {})[2];
}
getValue("date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||","kid_2");
But if you want something a little more involved, you can parse that string into a dictionary like so (fiddle):
function splitToDictionary(val, fieldDelimiter, valueDelimiter){
var dict = {},
fields = val.split(fieldDelimiter),
kvp;
for (var i = 0; i < fields.length; i++) {
if (fields[i] !== "") {
kvp = fields[i].split(valueDelimiter);
dict[kvp[0]] = kvp[1];
}
}
return dict;
}
var dict = splitToDictionary("date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||","||","::");
console.log(dict["date_1"]);
console.log(dict["date_2"]);
console.log(dict["kid_1"]);
console.log(dict["kid_2"]);
This works, here's my fiddle.
function getold_val(fieldname,str) {
var chunks = str.split('||');
for(var i = 0; i < chunks.length-1; i++) {
if(chunks[i].indexOf(fieldname) >= 0) {
return(chunks[i].substring(fieldname.length+2));
}
}
}
alert(getold_val('kid_2', 'date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||'));
The issue with your code was (as #slebetman noticed as well) the fact that a string index can be 0 because it starts exactly in the first letter.
The code is almost the same as yours, I just didn't use the second .split('::') because I felt a .substring(...) would be easier.
There are two bugs. The first error is in the indexOf call:
var n = str.indexOf(fieldname);
This will always return a value greater than or equal to 0 since the field exists in the string. What you should be doing is:
var n = chunks[k].indexOf(fieldname);
The second error is in your if statement. It should be:
if(n >= 0) {
...
}
or
if(n > -1) {
...
}
The substring you are looking for could very well be the at the beginning of the string, in which case its index is 0. indexOf returns -1 if it cannot find what you're looking for.
That being said, here's a better way to do what you're trying to do:
function getold_val(fieldName, str) {
var keyValuePairs = str.split("||");
var returnValue = null;
if(/||$/.match(str)) {
keyValuePairs = keyValuePairs.slice(0, keyValuePairs.length - 1);
}
var found = false;
var i = 0;
while(i < keyValuePairs.length && !found) {
var keyValuePair = keyValuePairs[i].split("::");
var key = keyValuePair[0];
var value = keyValuePair[1];
if(fieldName === key) {
returnValue = value;
found = true;
}
i++;
}
return returnValue;
}