Background
I'm new to JavaScript and am solving various formulations of the Josephus Problem to better understand the syntax. Using a circularLinkedList implementation*, I've solved the classic formulation: Wikipedia||Numberphile. I've also solved the problem for any fixed number of fighters and a fixed number of skips between eliminations (e.g., if skipping two fighters between eliminations, 1 eliminates 4, 5 eliminates 8, etc). I am now trying to solve the problem given any function that indicates the number of skips at a given moment.
Problem
I can't access the return value of my skip function. I understand from 1, 2, 3 that my issue involves asynchronicity, but am having trouble isolating takeaways from the long responses involving AJAX and jQuery, which I'm unfamiliar with. Could I get an ELI5 solution? I apologize for my lack of understanding.
Code
function winnerStepFunc(num, func) {
let cll = new circularLinkedList(); //Initializing list with participants
for (let a = 0; a < num; a++) {
cll.append(a);
}
function next(funcSteps) { //Generating string indicating #steps from function's output
let toEvaluate = "start";
for (let i = 0; i < funcSteps; i++) {
toEvaluate += ".next"
}
return toEvaluate;
}
let start = cll.getHead(); //Selecting first eliminator
while (cll.size() > 1) {
let toCheck = func(); // PROBLEM LINE
console.log("toCheck = " + toCheck); //toCheck = undefined
let str = next(toCheck);
while (eval(str) !== start && cll.size() > 1) { //
let locCurrent = cll.indexOf(start.element);
start = eval(str).next;
cll.removeAt(((locCurrent + toCheck)% cll.size()));
}
cll.delete(eval(str).next.element);
start = start.next;
}
console.log(start.element + 1);
}
function callFunction(name, args) { // builds function string to be evaluated
let result = name + "(";
for (let i = 0; i < args.length -1; i++) {
result += args[i] + ", ";
}
result += args[args.length-1] + ")";
return result;
}
function callFunction(name) {
let result = `${name}()`;
return result;
}
function addOne() { //<--The first basic example I'm trying:
return ++globalTimes; //Make the step increase by one for each elimination
}
var globalTimes = 0;
winnerStepFunc(12, function(){eval(callFunction("addOne"))});
*CLL Implementation
You don't return in your function. I would remove all the eval stuff and just call the function directly.
winnerStepFunc(12, addOne);
Related
How can i create this to console log like this?
String.prototype.sheldonize = function () {
return `knock ${this}`
}
'Penny'.sheldonize(3)
I have this code at the moment, but I dont know how to repeat knock more times
Use the repeat method to establish a number of 'knocks' in the line and to establish how many times the line should repeat
String.prototype.sheldonize = function (repeats) {
const line = `${'knock '.repeat(repeats)}${this}, `.repeat(repeats)
return `${line.substring(0,line.length-2)}.`;
}
console.log('Penny'.sheldonize(3));
Using For Loop and repeat method
String.prototype.sheldonize = function(count) {
let ans = "";
for (let i = 0; i < count; i++) {
ans += "knock ";
}
ans = `${ans}${this}, `.repeat(count)
ans = ans.substring(0, ans.length - 2) + "."
return ans;
}
console.log('Penny'.sheldonize(3))
console.log('Penny'.sheldonize(2))
Create an array and on each iteration up to n - 1 add the string to it, finally joining it up and returning the string from the function.
// If you're adding to a prototype it's always best
// to double check to see if the method already exists
// no matter (in this case) how unlikely
if (!('sheldonize' in String.prototype)) {
String.prototype.sheldonize = function (n) {
// Create the array
const out = [];
// Create the string
const knock = 'knock '.repeat(n);
// Loop until `n - 1` has been reached
// pushing the string into the array
// on each iteration
for (let i = 0; i < n; i++) {
out.push(`${knock}${this}`);
}
// Finally return the joined array
return out.join(', ');
}
}
console.log('Penny'.sheldonize(3));
console.log('Penny'.sheldonize(2));
console.log('John'.sheldonize(4));
Additional documentation
repeat
I am doing a modified version of collecting word co-occurrences, so I wrote my own javascript, and I am tracking the occurrences in three objects. However, once the objects get large (~8 million, 3 million, and 172000) a function that took 5 seconds per 100000 sentences now takes minutes to do one sentence with 30 words (30 tokens). I am nowhere near my RAM cap (I have 12 more GBs of RAM it could be using, and the program is only using 2.2GB). Using Node.js v17.3.1.
Why does my function take so long when the objects get bigger (even though the sentences remain the same length)? Should I be using a different object besides Javascript's default object, or is there a way improve the speed of access and setting these objects when they are so big?
Code:
let posCounts = {};
let negCounts = {};
// the number of times each word occurs
let wordCounts = {};
let tokens = // some function that gets tokens;
for (let k = 0; k < tokens.length; k++) {
// count word occurences
if (tokens[k] in wordCounts) {
wordCounts[tokens[k]] += 1;
} else {
wordCounts[tokens[k]] = 1;
}
for(let tok = k + 1; tok < tokens.length; tok++) {
if (tok == k) {
// avoid word to self cooccurrence
// should no longer be possible
continue;
} else {
// check which form of the cooccurence exists already in either count
actual_tok = (tokens[k] + "-" + tokens[tok]);
if(actual_tok in posCounts || actual_tok in negCounts) {
// no-op
} else {
actual_tok = (tokens[tok] + "-" + tokens[k]);
}
// condition set before this block of code
if(condition) {
if (actual_tok in posCounts) {
posCounts[actual_tok] += 1;
} else {
posCounts[actual_tok] = 1;
}
} else {
if (actual_tok in negCounts) {
negCounts[actual_tok] += 1;
} else {
negCounts[actual_tok] = 1;
}
}
}
}
}
Update: I've tried increasing the heap size via node train_matrices.js --max-old-space-size=12288 and node train_matrices.js --max_old_space_size=12288 (underline instead of dash), and that didn't work either.
Probably not the main issue in your code, but you can reduce the number of lookups by changing this structure from this:
if (tokens[k] in wordCounts) {
wordCounts[tokens[k]] += 1;
} else {
wordCounts[tokens[k]] = 1;
}
to this:
let token = tokens[k];
let cnt = wordCounts[token] || 0;
wordCounts[token] = cnt + 1;
And, as I said in a comment, I've read that a Map object with .get() and .set() is better suited when there are lots of dynamically created keys whereas plain objects are better suited when you have lots of objects with all the same keys (as the JS compiler can sometimes make a C-like struct for it), but this can't be done when you're regularly adding new keys.
The answer was to both use the increase memory flag node <YOUR_FILE_NAME>.js --max-old-space-size=12288 and change to using a Map instead of an object - thanks to #jfriend00 and #Norman Breau for the suggestions. That said, maps have a max capacity of 2^24 items or 1 GB, so I ended up using a modified version of the BigMap from this stackoverflow (modified to limit the total number of items still - ended up running completely out of RAM).
Modified code (you can replace BigMap with Map if you want):
let posCounts = new BigMap();
let negCounts = new BigMap();
let wordCounts = new BigMap();
let actual_tok;
tokens = // some code
// mark every cooccurrence
for (let k = 0; k < tokens.length; k++) {
// count word occurences
if (wordCounts.has(tokens[k])) {
wordCounts.set(tokens[k], wordCounts.get(tokens[k]) + 1);
} else {
wordCounts.set(tokens[k], 1);
}
for(let tok = k + 1; tok < tokens.length; tok++) {
if (tok == k) {
// avoid word to self cooccurrence
// should no longer be possible
continue;
} else {
// check which form of the cooccurence exists already in either count
actual_tok = (tokens[k] + "-" + tokens[tok]);
if(posCounts.has(actual_tok) || negCounts.has(actual_tok)) {
// no-op
} else {
actual_tok = (tokens[tok] + "-" + tokens[k]);
}
if(condition) {
if (posCounts.has(actual_tok)) {
posCounts.set(actual_tok, posCounts.get(actual_tok) + 1);
} else {
posCounts.set(actual_tok, 1);
}
} else {
if (negCounts.has(actual_tok)) {
negCounts.set(actual_tok, negCounts.get(actual_tok) + 1);
} else {
negCounts.set(actual_tok, 1);
}
}
}
}
}
}
So, I am trying to write a js function that takes 3 inputs (polynomial, guess and limit) and make them return the approximate root of the polynomial. The problem is that, even with a limit of 1000, the result is still very inaccurate. Does anybody have any ideas on why this may be?
The Method
The code:
var derivativeOfATerm = function(arr) {
var one = arr[0];
var two = arr[1];
var derivative = [];
if (two <= 0) {
return [0, 0];
} else {
derivative.push(one * two);
derivative.push(two - 1);
return derivative;
}
};
var derivativeOfPolynomial = function(arr, order = 1) {
var derivative = [];
for (var i = 0; i < arr.length; i++) {
//console.log(arr[i]);
derivative.push(derivativeOfATerm(arr[i]));
}
if (order === 1) {
return derivative;
} else {
return derivativeOfPolynomial(derivative, order - 1);
}
};
var runPolynomial = function(poly, num) {
var array = [];
for (var i = 0; i < poly.length; i++) {
array.push(Math.pow(num, poly[i][1]) * poly[i][0]);
}
return array.reduce((a, b) => a + b);
};
var newtonRootFind = function(polynomial, guess, limit = 10) {
var derivative = derivativeOfPolynomial(polynomial);
var previous = guess;
var next;
for (var i = 0; i < limit; i++) {
next = previous - (runPolynomial(polynomial, previous)) / (runPolynomial(derivative, previous));
previous = next;
console.log("%o : x=%o, p(x)=%o", i+1, next, runPolynomial(polynomial, next));
}
return previous;
};
console.log("result x=",newtonRootFind([[1,2],[1,1],[-5,0]], 5, 10));
I'm only 12 so try not to use that many technical terms.
For example, entering [[1,2],[1,1],[-5,0]] or x^2+x-5, it returns 1.79128784747792, which isn't accurate enough. It equals 4.79... when it should be very close to 5.
As worked out in the comments, the presented code works as intended, the problem was that in checking the solution x^2 was used for the square x*x.
However, x^y in most C- or Java-like languages is the bitwise "exclusive or", XOR, not the power operation. x^y as symbol for the power operation is usually found in Computer Algebra Systems. Script languages as python or gnuplot tend to use x**y.
I'm currently working on coderbyte's medium challenge entitled "Permutation Step."
The goal is to take user input, num, and to return the next number greater than num using the same digits So, for example, if user input is 123, then the number 132 should be returned. If user input is 12453, then 12534 should be returned...
Anywho, I have a correct model answer created by someone (probably a genius, cuz this stuff is pretty hard) and I'm trying to figure out how the answer works, line for line by having an example play out (I'm keeping it simple and playing out the function with user input 123).
The answer has 2 functions, but the 1st function used is what I'm currently trying to work out...
The relevant code is:
var PermutationStep1 = function(num) {
var num1 = num.toString();
var ar = [];
//return num1;
if (num1.length < 2) {
return num;
} else {
for(var i = 0; i < num1.length; i++) {
var num2 = num1[i];
var num3 = num1.substr(0,i) + num1.substr(i+1, num1.length -1);
var numAr = PermutationStep1(num3);
for(var j = 0; j < numAr.length; j++) {
ar.push(numAr[j] + num2);
}
}
ar.sort(function(a,b) {return a-b});
return ar;
}
}
Again, I'm trying to work thru this function with the inputted num as 123 (num = 123).
I'm pretty sure that this function should output an array with multiple elements, because the 2nd function merely compares those array elements with the original user input (in our case, 123), and returns the next greatest value.
So in our case, we should probably get an array, named 'ar', returned with a host of 3 digit values. But for some reason, I'm getting an array of 2 digit values. I can't seem to isolate my mistake and where I'm going wrong. Any help with where, specifically, I'm going wrong (whether it be the recursion, the use of substring-method, or the concating of strings together, whatever my problem may be) would be appreciated...
Here's some of my work so far:
PS1(123) / num1 = 123
i = 0;
num2 = (num1[i]) = '1';
num3 = (num1.substr(0, 0) + num1.substr(1, 2)) = ('0' + '23') = '23'
PS1(23)
i = 0;
num2 = '2';
num3 = '3'
PS1(3) -> numAr = 3 (since num1 is less than 2 digits, which is the recursion base case?)
(So take 3 into the 2nd for loop)...
ar.push(numAr[j] + num2) = ar.push('3' + '1') = 31
ar = [31] at this point
And then I go through the initial for-loop a couple more times, where i = 1 and then i = 2, and I eventually get....
ar = [31, 32, 33]...
But I'm thinking I should have something like ar = [131, 132, 133]? I'm not sure where I'm going wrong so please help. Because the answer is correctly spit out by this function, the correct answer being 132.
Note: if you need the 2nd part of the model answer (i.e. the 2nd function), here it is:
var arr = [];
function PermutationStep(num1) {
arr.push(PermutationStep1(num1));
var arrStr = arr.toString();
var arrStrSpl = arrStr.split(",");
//return arrStrSpl;
for(var p = 0; p < arrStrSpl.length; p++) {
if(arrStrSpl[p] > num1) {
return arrStrSpl[p];
}
}
return -1;
}
I'm sorry the first function i posted was under a mathematical logical mistake and i was to overhasty
I thought about it again and now i have the following function which definitley works
function getNextNumber (num)
{
var numberStr=num.toString (), l=numberStr.length, i;
var digits=new Array (), lighterDigits, digitAtWeight;
var weight,lightWeight, lighterDigits_l, value=0;
for (i=l-1;i>-1;i--)
digits.push (parseInt(numberStr.charAt(i)));
lighterDigits=new Array ();
lighterDigits.push (digits[0]);
for (weight=1;weight<l;weight++)
{
digitAtWeight=digits[weight];
lighterDigits_l=lighterDigits.length;
for (lightWeight=0;lightWeight<lighterDigits_l;lightWeight++)
{
if (digitAtWeight<lighterDigits[lightWeight])
{
lighterDigits.unshift (lighterDigits.splice (lightWeight,1,digitAtWeight)[0]);
lighterDigits.reverse ();
digits=lighterDigits.concat (digits.slice (weight+1,l));
for (weight=0;weight>l;weight++)
value+=Math.pow (10,weight)*digits[weight];
return value;
}
}
lighterDigits.push (digitAtWeight);
}
return NaN;
}
okay here is my solution i found it in 20 minutes ;)
//---- num should be a Number Object and not a String
function getNextNumber (num)
{
var numberStr=num.toString (), l=numberStr.length, i;
var digits=new Array (), digitA, digitB;
var weight,lightWeight;
var valueDifference,biggerValue;
for (i=l-1;i>-1;i--)
digits.push (parseInt(numberStr.charAt(i))); // 345 becomes a0=5 a1=4 a2=3 and we can say that num= a0*10^0+ a1*10^1+ a2*10^2, so the index becomes the decimal weight
for (weight=1;weight<l;weight++)
{
digitA=digits[weight];
biggerValue=new Array ();
for (lightWeight=weight-1;lightWeight>-1;lightWeight--)
{
digitB=digits[lightWeight];
if (digitB==digitA) continue;
valueDifference=(digitA-digitB)*(-Math.pow(10,weight)+Math.pow (10,lightWeight));
if (valueDifference>0) biggerValue.push(valueDifference);
}
if (biggerValue.length>0)
{
biggerValue.sort();
return (biggerValue[0]+num);
}
}
}
this is the solution I figured out for the problem without using a recursive function. It's passed all the tests on coderbyte. I am still new to this so using recursion is not the first thing I look for. hope this can help anyone else looking for a solution.
function PermutationStep(num) {
var numArr = (num + '').split('').sort().reverse();
var numJoin = numArr.join('');
for (var i = (num + 1); i <= parseInt(numJoin); i++){
var aaa = (i + '').split('').sort().reverse();
if (aaa.join('') == numJoin){
return i;
}
}
return -1;
}
I have a problem with this script, something is going wrong.
Rnumer stays undefined.This script should return and write all uneven digits from the random number list. Can someone tell me what I do wrong. Thanks in advance
var Rnumber = new Array();
for (i = 0; i<= 100;i++)
{
Rnumber[i] = Math.ceil(Math.random()*101);
// document.write(Rnumber[i] + "<br/>");
}
function unevenAndDivisible(Rnumber)
{
var remainder = new Array();
for (i = 0; i<= 100; i++)
{
remainder = parseInt(Rnumber[i])%2;
}
return remainder;
}
document.write(unevenAndDivisible());
Changed to
var Rnumber = new Array();
for (i = 0; i<= 100;i++)
{
Rnumber[i] = Math.ceil(Math.random()*101);
// document.write(Rnumber[i] + "<br/>");
}
function unevenAndDivisible(Rnumber)
{
var remainder = new Array();
for (i = 0; i<= 100; i++)
{
remainder[i] = Rnumber[i]%2;
}
return remainder;
}
document.write(unevenAndDivisible(Rnumber));
but now i get the result :
0,1,0,0,1,0,0,0,1,1,0,0,1,0,1,1,1....
I simply want maybe I asked it wrong the first time, to write al uneven numbers from the random list of Rnumbers
Then I need to divide that through 7 and return that.
EDIT
Allmost all problems are clear , thanks everyone for that.
Their is still one question left:
In this code below it only take the first uneven value from remainder and I want that it takes all values that are uneven to the next if statement to check %7.
Maybe you see the problem better if you run it for youreself
var Rnumber = new Array();
for (i = 0; i<= 100;i++)
{
Rnumber[i] = Math.ceil(Math.random()*101);
}
function unevenAndDivisible()
{
var remainder = [];
var answer = [];
for (i = 0; i<= 100; i++)
{
if (Rnumber[i]%2 !== 0)
{
remainder.push(Rnumber[i]);
for (c = 0; c <= remainder.length;c++)
{
if (remainder[c]%7 == 0)
{
answer.push(remainder[c]);
}
}
}
}
return answer;
}
answer = unevenAndDivisible();
document.write(answer);
Problem solved , Thanks everyone
You don't need to pass Rnumber to the function, as it's already available in scope:
function unevenAndDivisible()
{
var remainder = [];
for (i = 0; i<= 100; i++)
{
if (Rnumber[i]%2 !== 0) {
remainder.push(Rnumber[i]);
}
}
return remainder;
}
remainder = unevenAndDivisible();
console.log(remainder);
JS Fiddle demo.
Edited in response to question from OP (in comments to question, above):
...can someone explain what this mean: var remainder = [];
Sure, it's array-literal notation, which is equal to: var remainder = new Array();, it's just a little more concise, and I prefer to save myself the typing. I get the impression, from JS Lint, whenever I use var x = new Array(); therein that the above version is generally preferred (since it complains otherwise), but I don't know why.
Either pass Rnumber to the function unevenAndDivisible or omit it from the argument list. Since it is an argument, it has more local scope than the initial declaration of Rnumber.
Your problem is the line
function unevenAndDivisible(Rnumber)
You are passing in Rnumber in as an argument, but when you call unevenAndDivisible()
you are not passing it it.
Consequently for the body of the function Rnumber is undefined (cause you passed nothing in)
The following snippet is equivalent to what you wrote nad might explain better
function unevenAndDivisible(xyz)
{
var remainder = new Array();
for (i = 0; i<= 100; i++)
{
remainder = parseInt(xyz[i])%2;
}
return remainder;
}
then called as
unevenAndDivisible(undefined)
to fix it remove the argument from the call definition
i.e. define it as
function unevenAndDivisible()
1 - you is not defining the Rnumber value that's function argument.
2 - in loop, you're defining remainder to divised value of ranumber and is not saving in array; try:
change:
remainder = parseInt(Rnumber[i])%2;
to
remainder[i] = parseInt(Rnumber[i])%2;
var array = [],
i = 100;
while (i--) {
var random = Math.random()*i|0;
if(random % 2)
array.unshift(random);
}
alert(array);