How do I convert a string into a bitmask in javascript? - javascript

Now, this is simple enough when the numbers are small, but numbers like "9223372036854775807" are too large for parseInt().
I'm not sure how to do this within the Google docs script editor, which doesn't seem to allow for external classes.

Here you go, used this script somewhere and it seems to work. The idea behind it is that it splits the string to 8-character chunks, and calculates chunk/2, then sums the chunks up and gets a result of division by 2.
By dividing by 2 - it easily calculates the result then.
var maxIntSize = 8;
function divide2(number, addup, depth) {
var result = "";
var partLength = Math.min(number.length,maxIntSize);
var part = number.substring(0,partLength);
var partNum = parseInt(part,10);
var partAdd = (addup==0)?0:(5*Math.pow(10,partLength-1));
var partRes = Math.floor(partNum/2)+partAdd;
var partRem = partNum%2;
result = result + partRes;
if (depth > 0) {
for (var i=result.length; i < partLength; i++) {
result = "0"+result;
}
}
var nextPart = number.substring(partLength, number.length);
if (partLength < number.length) {
var res = divide2(nextPart, partRem, depth+1);
result = result + res.result;
res.result = result;
return res;
} else {
var res = {result: result, remainder: partRem};
return res;
}
}
function toBinary(number) {
var out = "";
while (number.length > 1 || number != "0") {
var res = divide2(number,0,0);
out = "" + res.remainder + out;
number = res.result;
}
return out;
}
var testNum = "12312312312112312312312312312312312312312312312312312312312312312312312312312312312312312312123";
document.write("bin("+testNum+") = "+toBinary(""+testNum)+"<br/>");
Division to chunks is required to calculate division by 2 faster. This script works pretty fast even for huge numbers.

Related

Check if String has sequential or repeated characters in javascript (underscore)

I have code that I am trying to refactor. Im new to javascript so Im tring to make more readable code using functions in libraries like underscore.
The function below can detect when string
contains 3 or more ordered characters such as (234, efg, LmN)
and
when string contains 3 or more repeated (lll, 444, MMm, ###)
const input = "Dfdf123125";
const myStr = input.toLowerCase();
const n = 3;
let isRepeating = false;
let isSequential = false;
for (let i = 0; i < myStr.length; i++) {
if (i + (n - 1) <= myStr.length) {
let isRepeatingTemp = false;
let isSequentialTemp = false;
for (let j = i; j < i + n; j++) {
(myStr.charCodeAt(i) === myStr.charCodeAt(j)) ? isRepeatingTemp = true: isRepeatingTemp = false;
(myStr.charCodeAt(i) === myStr.charCodeAt(j) - (n - 1)) ? isSequentialTemp = true : isSequentialTemp = false;
}
if (isRepeatingTemp) isRepeating = true;
if (isSequentialTemp) isSequential = true;
}
}
Im trying to to see if I can optimize this and make it more readable with underscore and/or even make time/space complexity better. I know this can also be done with regx but im trying to get it done without it.
Instead of the inner for loop, I chunked the string to n using Array.prototype.slice() to see ahead n characters. I used Array.prototype.indexOf() to find if it's sequential based off the abc and num constants(ref). To see if it's repeating, I used Array.prototype.every() that loops through the chunk and check if they're similar and return a boolean based on the expression.
The result gives the output of each instance found, and if it was sequential or repeating.
const input = "Dfdf123125";
function RepSeq(str, n) {
var rep = false;
var seq = false;
var result = [];
const num = '0123456789';
const abc = 'abcdefghijklmnopqrstuvqxyz';
if (str.length < n) return false;
for (var i = 0; i < str.length; i++) {
if (i + n > str.length) break;
var chunk = str.slice(i, i + n);
var seqABC = abc.indexOf(chunk) > -1;
var seq123 = num.indexOf(chunk) > -1;
if (seq123 || seqABC) {
seq = true;
result.push(chunk);
}
if ([...chunk].every(v => v.toLowerCase() === chunk[0].toLowerCase())) {
rep = true;
result.push(chunk);
}
}
return {
repetition: rep,
sequential: seq,
out: result
};
}
console.log(RepSeq(input, 3));
// Output:
// {
// out: ["123"],
// repetition: false,
// sequential: true
// }
With this method, we're peeking at the string one block(i+n) at a time. Ex(n=3):
1. [Dfd]f123125
2. D[fdf]123125
3. Df[df1]23125
4. Dfd[f12]3125
5. Dfdf[123]125 - Sequential!
6. Dfdf1[231]25
7. Dfdf12[312]5
8. Dfdf123[125]

Shorten array if total length of strings is longer than specified value (for loop) - JavaScript

I'm trying to shorten a text, if it is longer than a specified number.
So shorten_text_easy(text, 30), should return "We believe. In the future".
The first loop is working and displaying the correct total length of the strings in the array, but the second is where the error is, but I can't seem to find the issue.
var text = "We believe. In the future. The future is here. This is a test. We are testing.";
function shorten_text_easy(text, number) {
var text_array = text.split('. ').join('.///').split('///'); // Splitting the text into an array
var text_array_length = text_array.length;
var total_text_array_length = 0; // Predefining value to zero; The total length of all strings in the array
for (var i = 0; i < text_array_length; i++) { // To run while i is short than the length of the array
total_text_array_length += text_array[i].length; //
}
total_text_array_length = total_text_array_length + text_array_length - 1; // To exclude spaces which are omitted in array
console.log(total_text_array_length); // To show in console the first value of total_array_length
for (total_text_array_length; total_text_array_length > number; text_array.pop(-1), text_array_length--) { // Trying to remove the last item of an array if the total length of all strings in the array is larger than the number
for (var i = 0; i < text_array_length; i++) {
total_text_array_length += text_array[i].length;
console.log(total_text_array_length);
}
total_text_array_length = total_text_array_length + text_array_length - 1;
}
return text_array // This should return the end text array, when the total length of all strings is lower than 'number'
};
console.log(
shorten_text_easy(text, 30)
);
Slicing on last full stop that fits
const shorten_text_easy = (text, number) => {
let res = text.slice(0,number);
const pos = res.lastIndexOf(".");
return pos > 0 ? res.slice(0,pos+1) : res;
}
var text = "We believe. In the future. The future is here. This is a test. We are testing.";
console.log(
shorten_text_easy(text, 30)
);
I ended up doing this:
function shortenTextNextDot (text, length) {
var firstDot = text.indexOf(".") + 1;
if (length <= firstDot) {
return text.slice(0, firstDot);
} else {
var textLength = text.slice(0, length);
var restText = text.slice(length);
var nextDot = restText.indexOf(".") + 1;
var finalSentence = textLength + restText.slice(0, nextDot);
return finalSentence;
}
}
function shortenTextPrevDot (text, length) {
var firstDot = text.indexOf(".") + 1;
if (length <= firstDot) {
return text.slice(0, firstDot);
} else {
var textLength = text.slice(0, length);
var lastDot = textLength.lastIndexOf(".") + 1;
var finalSentence = textLength.slice(0, lastDot);
return finalSentence;
}
}

Getting Incorrect range height for seemingly no reason?

I am writing a script to copy and paste a range from one sheet to another. The pasted range size should be reduced by using two functions : one to delete rows with specific values and the other is an aggregate function.
I started getting this error after I introduced the aggregate function The function is basically reducing the array size using the reduce JS function.
I have replicated my problem here and the code is accessible in the script editor.
When I run the script I am getting the following error :
Incorrect range height was 28 but should be 7 (line 36, file "test")
I have no idea why am I getting this error. My aggregate function returns a properly formatted array with the right length.
function append_range(){
var origin_sheet = SpreadsheetApp.openById('1-2ZheMz1p01qwtwY3ghbNjJedYfGXeylnLEjDMCLpMw');//open the file
origin_sheet = origin_sheet.getSheetByName('test');
var rangeStart = 2;
var range = origin_sheet.getRange('A'+ (rangeStart.toString())+':T'+ (origin_sheet.getLastRow()).toString());
var dataFromRange = range.getValues();
var dataFromRangeLength = dataFromRange.length;
var destination_sheet = SpreadsheetApp.openById('1-2ZheMz1p01qwtwY3ghbNjJedYfGXeylnLEjDMCLpMw');
destination_sheet = destination_sheet.getSheetByName('append');
var rowLast = destination_sheet.getLastRow()+1;
Logger.log("row last" + rowLast);
var formattedRange = deleteRows(dataFromRange);
var groups = aggregate(formattedRange);
var aggregates = [];
for(var group in groups)
{
aggregates.push(groups[group]);
}
Logger.log(aggregates);
var formattedRangeLength = aggregates.length;
Logger.log("formattedRangeLength" + formattedRangeLength);
destination_sheet.getRange(rowLast,1,formattedRangeLength, 20).setValues(deleteRows(dataFromRange));
function isDate(sDate) {
if (isValidDate(sDate)) {
sDate = Utilities.formatDate(new Date(sDate), "PST", "yyyy-MM-dd");
}
return sDate;
}
function isValidDate(d) {
if ( Object.prototype.toString.call(d) !== "[object Date]" )
return false;
return !isNaN(d.getTime());
}
//
function deleteRows(dataRange){//just pass the range in an array and this method will return another array with filtered range
var formatted = dataRange.filter(function(e) {
return e[8]||e[9]||e[10]||e[11]||e[12]||e[13]||e[14]||e[15]||e[16]||e[17]||e[18]||e[19];
});
return formatted;
}
function aggregate(data)
{
var groups = data.reduce(
function(accumulator, previous){
{
var key = previous[1] + previous[3] + previous[5] + previous[6];
var group = accumulator[key];
if(group == null || typeof group == 'undefined')
{
accumulator[key] = previous;
}
else {
var startIndex = 8;
for(var i = startIndex; i < previous.length;i++)
{
group[i] += previous[i];
}
}
return accumulator;
}},
{});
return groups;
}
}
The .setValues() is not setting your aggregates array it is trying to set deleteRows(dataFromRange)
// Change the setValues() to your reduced array
destination_sheet.getRange(rowLast,1,formattedRangeLength, 20).setValues(aggregates);
I think this might work:
var output=deleteRows(dataFromRange));
destination_sheet.getRange(rowLast,1,output.length, output[0].length).setValues(deleteRows(output));
This assumes a non jagged array.

Javascript: reducing down to one number

So I need to take a date and convert it into one single number by adding up each digit, and when the sum exceeds 10, I need to add up the two digits. For the code below, I have 12/5/2000, which is 12+5+2000 = 2017. So 2+0+1+7 = 10 & 1+0 = 1. I get it down to one number and it works in Firebug (output of 1). However, it is not working in a coding test environment I am trying to use, so I suspect something is wrong. I know the code below is sloppy, so any ideas or help reformatting the code would be helpful! (Note: I am thinking it has to be a function embedded in a function, but haven't been able to get it to work yet.)
var array = [];
var total = 0;
function solution(date) {
var arrayDate = new Date(date);
var d = arrayDate.getDate();
var m = arrayDate.getMonth();
var y = arrayDate.getFullYear();
array.push(d,m+1,y);
for(var i = array.length - 1; i >= 0; i--) {
total += array[i];
};
if(total%9 == 0) {
return 9;
} else
return total%9;
};
solution("2000, December 5");
You can just use a recursive function call
function numReduce(numArr){
//Just outputting to div for demostration
document.getElementById("log").insertAdjacentHTML("beforeend","Reducing: "+numArr.join(","));
//Using the array's reduce method to add up each number
var total = numArr.reduce(function(a,b){return (+a)+(+b);});
//Just outputting to div for demostration
document.getElementById("log").insertAdjacentHTML("beforeend",": Total: "+total+"<br>");
if(total >= 10){
//Recursive call to numReduce if needed,
//convert the number to a string and then split so
//we will have an array of numbers
return numReduce((""+total).split(""));
}
return total;
}
function reduceDate(dateStr){
var arrayDate = new Date(dateStr);
var d = arrayDate.getDate();
var m = arrayDate.getMonth();
var y = arrayDate.getFullYear();
return numReduce([d,m+1,y]);
}
alert( reduceDate("2000, December 5") );
<div id="log"></div>
If this is your final code your function is not outputting anything. Try this:
var array = [];
var total = 0;
function solution(date) {
var arrayDate = new Date(date);
var d = arrayDate.getDate();
var m = arrayDate.getMonth();
var y = arrayDate.getFullYear();
array.push(d,m+1,y);
for(var i = array.length - 1; i >= 0; i--) {
total += array[i];
};
if(total%9 == 0) {
return 9;
} else
return total%9;
};
alert(solution("2000, December 5"));
It will alert the result in a dialog.

for loop not executing properly Javascript

i m trying to calculate weight of a string using the following function
function weight(w)
{
Cap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
small = 'abcdefghijklmnopqrstuvwxyz'
spcl = "~!##$%^&*()_+[]\{}|;':,./<>?"
num = '0123456789'
var p = []
for(i=0;i<w.length;i++)
{
if(Cap.contains(w[i])==true)
p[i] = Cap.indexOf(w[i]) + 2
else if(small.contains(w[i])==true)
p[i] = small.indexOf(w[i]) + 1
else if(num.contains(w[i]))
p[i] = num.indexOf(w[i])
else if(spcl.contains(w[i]))
p[i] = 1
}
return _.reduce(p,function(memo, num){ return memo + num; }, 0);
}
where w is a string. this properly calculates weight of the string.
But whn i try to to calculate weight of strings given in a an array, it jst calculates the weight of the first element, ie. it does not run the full for loop. can anyone explain to me why is that so??
the for loop is as given below
function weightList(l)
{
weigh = []
for(i=0;i<l.length;i++)
weigh.push(weight(l[i]));
return weigh;
}
input and output:
>>> q = ['abad','rewfd']
["abad", "rewfd"]
>>> weightList(q)
[8]
whereas the output array should have had 2 entries.
[8,56]
i do not want to use Jquery. i want to use Vanilla only.
Because i is a global variable. So when it goes into the function weight it sets the value of i greater than the lenght of l. Use var, it is not optional.
for(var i=0;i<l.length;i++)
and
for(var i=0;i<w.length;i++)
You should be using var with the other variables in the function and you should be using semicolons.
I think your issue is just malformed JavaScript. Keep in mind that JavaScript sucks, and is not as forgiving as some other languages are.
Just by adding a few "var" and semicolons, I was able to get it to work with what you had.
http://jsfiddle.net/3D5Br/
function weight(w) {
var Cap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
small = 'abcdefghijklmnopqrstuvwxyz',
spcl = "~!##$%^&*()_+[]\{}|;':,./<>?",
num = '0123456789',
p = [];
for(var i=0;i<w.length;i++){
if(Cap.contains(w[i])==true)
p[i] = Cap.indexOf(w[i]) + 2
else if(small.contains(w[i])==true)
p[i] = small.indexOf(w[i]) + 1
else if(num.contains(w[i]))
p[i] = num.indexOf(w[i])
else if(spcl.contains(w[i]))
p[i] = 1
}
return _.reduce(p,function(memo, num){ return memo + num; }, 0);
}
function weightList(l) {
var weigh = [];
for(var i=0;i<l.length;i++)
weigh.push(weight(l[i]));
return weigh;
}
q = ['abad','rewfd'];
results = weightList(q);
Hope that helps

Categories

Resources