So, first and foremost, it's important to note that I'm adding a feature to something I didn't design. I'm really new to JavaScript, and I'm trying to edit an existing Discord bot. I discovered that the simplest way to achieve my goal would be to edit the root function at which it generates Random numbers. The relavant snippet of the original code (taken from the dice-expression-evaluator module https://github.com/dbkang/dice-expression-evaluator) is as follows:
Dice.prototype.roll = function () {
var rolls = [];
var sum = 0;
for (var i = 0; i < this.diceCount; i++) {
var roll = random.integer(1, this.sideCount) * this.coefficient;
rolls.push(roll);
sum += roll;
}
return {roll: sum, dice: rolls};
};
This original code works just fine, but doesn't include my desired feature (a simple-but-verbose sort of whitelist.) the 4 variables not defined in that particular code block are rather self-explanatory. My version of the code (slightly edited for privacy reasons) is as follows:
Dice.prototype.roll = function () {
var rolls = [];
var sum = 0;
var range = this.whitelist(); //already tried it with () after whitelist
console.log(range.join(','));
for (var i = 0; i < this.diceCount; i++) {
var roll = random.integer(range[0], range[1]) * this.coefficient; //changed the 2 function arguments, but both are still integers
rolls.push(roll);
sum += roll;
}
return {roll: sum, dice: rolls};
};
Dice.prototype.whitelist = function () {
let user0 = "a";
let user1 = "b";
let user2 = "c";
let user3 = "d";
let user = message.author.id;
let die = this.sideCount;
console.log(user);
console.log(string(die));
if (user==user0) {
var min = Math.ceil(0.76 * die);
var max = die;
} else if (user==user1) {
var min = Math.ceil(0.76 * die);
var max = die;
} else if (user==user2) {
var min = 1;
var max = die;
} else if (user==user3) {
var min = 1;
var max = die;
} else {
var min = 1;
var max = die;
}
return [min, max];
};
The message.author.id variable is available to the function that started the whole function chain 3 scopes up, but in MY version of the code, (even after correcting a few missing semicolons and similarly minute errors) a dice expression that is perfectly functional in the original code generates an "invalid dice expression" error. Other than the introduction of a new variable and the variables in the random.integer call, I see no functional difference between the old and new versions of Dice.prototype.roll. By my understanding, my whitelist function returns an array of integers, and those integers are being injected directly into the random.integer function call in a perfectly reasonable way... I am incredibly confused.
I have the following code
var utils = require(`${__dirname}/../../utils/utils.js`);
...
let object = utils.parse(input);
if (object === undefined){
let helper = utils.recognize(input);
msg.channel.sendMessage("\"" + input + "\" not recognized. Did you mean \"" + helper[0] + "\"?");
object = utils.parse(helper[0]);
}
//code related to object
console.log(object.strLength);
where "parse" tries to match the input to an object in a database, and "recognize" tries to find the best match if the input is spelled incorrectly (Levenshtein) (along with additional info such as how close the match was).
Currently the issue is that the code is ran asynchronously; "object.strLength" returns an undefined before utils.recognize() returns a value. If I copy/paste the recognize() and parse() functions into the file, then the code is run synchronously and I do not run into any issues. However I would rather keep those functions in a separate file as I reuse them in other files.
Is there a way to specify that the functions in utils must be synch? I know that there are libraries that convert asynch into synch but I prefer to use as few libraries as I can help it. I tried to have the recognize functions return a Promise but it ended up as a jumbled mess
edit: here's parse. I did not think it was necessary to answer this question so I did not include it initially:
var db = require(`${__dirname}/../data/database.js`);
...
var parse = (input) => {
let output = db[output];
if (output === null) {
Object.keys(db).forEach((item) => {
if (db[item].num === parseInt(input) || (db[item].color + db[item].type === input)){
output = db[item];
return false;
}
});
}
return output;
}
I solved the issue, thanks everyone. Here's what was wrong, it was with recognize(). It was my mistake to not show the code for it initially.
Original recognize:
var recognize = (item) => {
//iterate through our databases and get a best fit
let bestItem = null;
let bestScore = 99999; //arbitrary large number
//let bestType = null;
//found algorithm online by milot-mirdita
var levenshtein = function(a, b) {
if (a.length == 0) { return b.length; }
if (b.length == 0) { return a.length; }
// swap to save some memory O(min(a,b)) instead of O(a)
if(a.length > b.length) {
let tmp = a;
a = b;
b = tmp;
}
let row = [];
for(let i = 0; i <= a.length; i++) {
row[i] = i;
}
for (let i = 1; i <= b.length; i++) {
let prev = i;
for (let j = 1; j <= a.length; j++) {
let val;
if (b.charAt(i-1) == a.charAt(j-1)) {
val = row[j-1]; // match
} else {
val = Math.min(row[j-1] + 1, // substitution
prev + 1, // insertion
row[j] + 1); // deletion
}
row[j - 1] = prev;
prev = val;
}
row[a.length] = prev;
}
return row[a.length];
}
//putting this here would make the code work
//console.log("hi");
Object.keys(db).forEach((key) => {
if (levenshtein(item, key) < bestScore) {
bestItem = key;
bestScore = levenshtein(item, key);
}
});
return [bestItem, bestScore];
}
My solution was to move the levenshtein function outside of the recognize function, so if I wanted to I can call levenshtein from another function
#user949300 and #Robert Moskal, I changed the forEach loop into a let...in loop. There is no functional difference (as far as I can tell) but the code does look cleaner.
#Thomas, I fixed the let output = db[output]; issue, oops.
Again, thanks for all of your help, I appreciate it. And happy New Year too
The following code counts the no. of inversions in an array. It is always recursively getting divided into sub-problems until the stack error, RangeError: Maximum call stack size exceeded occurs even when the base case is defined. What could be the issue here
function mergeSort(arr) {
var n = arr.length;
var l=0,h=n-1;
if (l<h) {
var m=findMid(l,h);
var leftArr=arr.slice(l,m);
var rightArr=arr.slice(m,n);
var invCount = mergeSort(leftArr)+mergeSort(rightArr);
invCount += merge(leftArr,rightArr,n);
}
return invCount;
}
function merge(a, b,n) {
var i=0,j=0,m=[];
var splitInv=0;
for(var k=0;k<n;k++) {
if(a[i]<b[j]) m[k]=a[i++];
else if (b[j]<a[i]){
m[k]=b[j++];
splitInv+=n-i;
}
}
return splitInv;
}
function findMid(l, r) {
var m = Math.floor((l + r) / 2);
return m;
}
I had modified the above code to handle the base cases in a different way. Is the following logic correct:
function mergeSort(arr) {
var n = arr.length;
var l=0,h=n-1;
var invCount=0;
if(n<=2) {
return merge(arr[0],arr[1],n);
}else{
var m=Math.floor(n/2);
var leftArr=arr.slice(l,m);
var rightArr=arr.slice(m);
invCount += mergeSort(leftArr)+mergeSort(rightArr);
}
return invCount;
}
function merge(a, b,n) {
var i=0,j=0,m=[];
var splitInv=0;
if(typeof b=="undefined") {
return 0;
}
for(var k=0;k<n;k++) {
if(a[i]<b[j]) m[k]=a[i++];
else if (b[j]<a[i]){
m[k]=b[j++];
splitInv+=n-i;
}
}
return splitInv;
}
RangeError is coming due to too much recursive call to mergeSort.
For the size of arr 2 size of rightArr will remain 2.
Instead of
var rightArr=arr.slice(m,n);
You may do
var rightArr=arr.slice(m+1,n);
Same question posted here, Javascript implementation of the inversion-counting with merge-sort algorithm. This describes everything that you need.
I have a javascript object that I am passing through a websocket as raw text to a client. This raw text (for now) is directly passed into an eval statement when received. The issue is, for some reason, Javascript keeps manipulating the data before passing it to the event handler. I am at wits end.
The object that is being passed across the websocket is:
var obj = {
evaluate:function(str) {
digit = parseInt(str,10);
if(isNaN(digit)) {
log.write("Invalid input: "+str);
} else {
log.write(this.spigot(digit));
}
},
spigot:function(digit) {
len = Math.floor(10*digit/3)+1;
A = new Array(len);
for(var i=0;i<len;i++) A[i]=2;
var finalDigit = 0;
var nines = 0;
var predigit = 0;
for(i=1;i<digit+1;i++) {
q = 0;
for(j=len;j>0;j--) {
x = 10*A[j-1] + q*j;
x = Math.floor(x)
A[j-1] = x % ((2*j)-1);
A[j-1] = Math.floor(A[j-1]);
q = x / ((2*j) -1);
q = Math.floor(q);
}
A[0] = Math.floor(q%10);
q = Math.floor(q/10);
if(q==9) {
nines++;
} else if (q==10) {
finalDigit = predigit+1;
for(j=0;j<nines;j++) {
finalDigit = 0;
}
predigit=0;
nines=0;
} else {
finalDigit = predigit;
predigit=q;
for(j=0;j<nines;j++) {
finalDigit = 9;
}
nines=0;
}
}
return finalDigit;
}
}
The client receives the message whole (I checked using both Chrome's developer tools and Firebug). However when I get the message in the following event handler:
function socketMessage(e) {
log.write(e.data); //a log function I have written
}
e.data contains:
obj = {
evaluate:function(str) {
digit = parseInt(str,10);
if(isNaN(digit)) {
log.write('Invalid input: '+str);
} else {
log.write(this.spigot(digit));
}
},
spigot:function(digit) {
len = Math.floor(10*digit/3)+1;
A = new Array(len);
for(var i=0;i<len;i++) A[i]=2;
var finalDigit = 0;
var nines = 0;
var predigit = 0;
for(i=1;i<digit+1;i++) {
q = 0;
for(j=len;j>0;j--) {
x = 10*A[j-1] + q*j;
x = Math.floor(x)
A[j-1] = x %((MISSING)(2*j)-1);
A[j-1] = Math.floor(A[j-1]);
q = x / ((2*j) -1);
q = Math.floor(q);
}
A[0] = Math.floor(q%)(MISSING);
q = Math.floor(q/10);
if(q==9) {
nines++;
} else if (q==10) {
finalDigit = predigit+1;
for(j=0;j<nines;j++) {
finalDigit = 0;
}
predigit=0;
nines=0;
} else {
finalDigit = predigit;
predigit=q;
for(j=0;j<nines;j++) {
finalDigit = 9;
}
nines=0;
}
}
return finalDigit;
}
}
Note how the code has been mutated. There are random (MISSING) strings added throughout it and several of the equations have been truncated.
Why is this happening?
EDIT 1:
After playing around for a while, I have noticed it happens after the % symbol regardless of its placement... So my question is, why significance does the % operator have here that is causing the event listener to slaughter the content of my code?
EDIT 2:
It would appear % is being interpreted as an escape character before being passed to my callback function. I've tried using %25 before sending it across the socket but to no avail.
The % character is being interpreted as an escape character by Javascript. The (MISSING) text you see added is Javascript's way of telling you the escape character wasn't followed by a two digit escape code. The easiest way around this problem is to define a function mod(a,b) that accomplishes the same thing as modulus. I.E.:
....},
mod:function(a,b) {
return (a/b-Math.floor(a/b))*b;
}
Then when you need to use the modulus operator, simply call
Math.floor(this.mod(q,10));
I'd like to use console.log() to log messages without appending a new line after each call to console.log(). Is this possible?
No, it's not possible. You'll have to keep a string and concatenate if you want it all in one line, or put your output elsewhere (say, another window).
In NodeJS you can use process.stdout.write and you can add '\n' if you want.
console.log(msg) is equivalent to process.stdout.write(msg + '\n').
Yes, it's possible (check out the demo below) -- by implementing your own virtual console on top of the native browser console, then syncing it to the real one.
This is much easier than it sounds:
maintain a display buffer (e.g. an array of strings representing one line each)
call console.clear() before writing to erase any previous contents
call console.log() (or warn, error, etc) to fill the console with the contents from your display buffer
Actually, I've been doing this for some time now. A short, rudimentary implementation of the idea would be something along the following lines, but still capable of animating the console contents:
// =================================================
// Rudimentary implementation of a virtual console.
// =================================================
var virtualConsole = {
lines: [],
currentLine: 0,
log: function (msg, appendToCurrentLine) {
if (!appendToCurrentLine) virtualConsole.currentLine++;
if (appendToCurrentLine && virtualConsole.lines[virtualConsole.currentLine]) {
virtualConsole.lines[virtualConsole.currentLine] += msg;
} else {
virtualConsole.lines[virtualConsole.currentLine] = msg;
}
console.clear();
virtualConsole.lines.forEach(function (line) {
console.log(line);
});
},
clear: function () {
console.clear();
virtualConsole.currentLine = 0;
}
}
// =================================================
// Little demo to demonstrate how it looks.
// =================================================
// Write an initial console entry.
virtualConsole.log("Loading");
// Append to last line a few times.
var loadIndicatorInterval = setInterval(function () {
virtualConsole.log(".", true); // <- Append.
}, 500);
// Write a new line.
setTimeout(function () {
clearInterval(loadIndicatorInterval);
virtualConsole.log("Finished."); // <- New line.
}, 8000);
It sure has its drawbacks when mixing with direct console interaction, and can definitely look ugly -- but it certainly has its valid uses, which you couldn't achieve without it.
You can put as many things in arguments as you'd like:
console.log('hi','these','words','will','be','separated','by','spaces',window,document)
You'll get all that output on one line with the object references inline and you can then drop down their inspectors from there.
The short answer is no.
But
If your use-case involves attempting to log perpetually changing data while avoiding console-bloat, then one way to achieve this (in certain browsers) would be to use console.clear() before each output.
function writeSingleLine (msg) {
console.clear();
console.log(msg);
}
writeSingleLine('this');
setTimeout( function () { writeSingleLine('is'); }, 1000);
setTimeout( function () { writeSingleLine('a'); }, 2000);
setTimeout( function () { writeSingleLine('hack'); }, 3000);
Note that this would probably break any other logging functionality that was taking place within your application.
Disclaimer: I would class this as a hack.
collect your output in an array and then use join function with a preferred separator
function echo(name, num){
var ar= [];
for(var i =0;i<num;i++){
ar.push(name);
}
console.log(ar.join(', '));
}
echo("apple",3)
check also Array.prototype.join() for mode details
var elements = ['Fire', 'Wind', 'Rain'];
console.log(elements.join());
// expected output: Fire,Wind,Rain
console.log(elements.join(''));
// expected output: FireWindRain
console.log(elements.join('-'));
// expected output: Fire-Wind-Rain
If your only purpose to stop printing on many lines, One way is to group the values if you don't want them to fill your complete console
P.S.:- See you browser console for output
let arr = new Array(10).fill(0)
console.groupCollapsed('index')
arr.forEach((val,index) => {
console.log(index)
})
console.groupEnd()
console.group
console.groupCollapsed
Something about #shennan idea:
function init(poolSize) {
var pool = [];
console._log = console.log;
console.log = function log() {
pool.push(arguments);
while (pool.length > poolSize) pool.shift();
draw();
}
console.toLast = function toLast() {
while (pool.length > poolSize) pool.shift();
var last = pool.pop() || [];
for (var a = 0; a < arguments.length; a++) {
last[last.length++] = arguments[a];
}
pool.push(last);
draw();
}
function draw() {
console.clear();
for(var i = 0; i < pool.length; i++)
console._log.apply(console, pool[i]);
}
}
function restore() {
console.log = console._log;
delete console._log;
delete console.toLast;
}
init(3);
console.log(1);
console.log(2);
console.log(3);
console.log(4); // 1 will disappeared here
console.toLast(5); // 5 will go to row with 4
restore();
A simple solution using buffered output. Works with deno and should work with node.js. (built for porting pascal console programs to javascript)
const write = (function(){
let buffer = '';
return function (text='\n') {
buffer += text;
let chunks = buffer.split('\n');
buffer = chunks.pop();
for (let chunk of chunks)
{console.log(chunk);}
}
})();
function writeln(text) { write(text + '\n'); }
To flush the buffer, you should call write() at the end of program.
If you mix this with console.log calls, you may get garbage output.
if you want for example console log array elements without a newline you can do like this
const arr = [1,2,3,4,5];
Array.prototype.log = (sep='') => {
let res = '';
for(let j=0; j<this.lengthl j++){
res += this[j];
res += sep;
}
console.log(res);
}
// console loging
arr.log(sep=' '); // result is: 1 2 3 4 5
Useful for debugging or learning what long chained maps are actually doing.
let myConsole = (function(){
let the_log_buffer=[[]], the_count=0, the_single_line=false;
const THE_CONSOLE=console, LINE_DIVIDER=' ~ ', ONE_LINE='ONE_LINE',
PARAMETER_SEPARATOR= ', ', NEW_LINE = Symbol();
const start = (line_type='NOT_ONE_LINE') => {
the_log_buffer=[[]];
the_count=0;
the_single_line = line_type == ONE_LINE;
console = myConsole;
}
const stop = () => {
isNewline();
console = THE_CONSOLE;
};
const isNewline = a_param => {
if (the_single_line && a_param==NEW_LINE) return;
const buffer_parts = the_log_buffer.map(one_set=> one_set.join(PARAMETER_SEPARATOR))
const buffer_line = buffer_parts.join(LINE_DIVIDER);
if (the_single_line) {
THE_CONSOLE.clear();
}
THE_CONSOLE.log( buffer_line );
the_log_buffer = [[]];
the_count=0;
}
const anObject = an_object => {
if (an_object instanceof Error){
const error_props = [...Object.getOwnPropertyNames(an_object)];
error_props.map( error_key => an_object['_' + error_key] = an_object[error_key] );
}
the_log_buffer[the_count].push(JSON.stringify(an_object));
}
const aScalar = a_scalar => {
if (typeof a_scalar === 'string' && !isNaN(a_scalar)) {
the_log_buffer[the_count].push("'" + a_scalar + "'");
} else {
the_log_buffer[the_count].push(a_scalar);
}
}
const notNewline = a_param => typeof a_param === 'object' ? anObject(a_param):aScalar(a_param);
const checkNewline = a_param => a_param == NEW_LINE ? isNewline(a_param) : notNewline(a_param);
const log = (...parameters_list) => {
the_log_buffer[the_count]=[];
parameters_list.map( checkNewline );
if (the_single_line){
isNewline(undefined);
}else{
const last_log = parameters_list.pop();
if (last_log !== NEW_LINE){
the_count++;
}
}
}
return Object.assign({}, console, {start, stop, log, ONE_LINE, NEW_LINE});
})();
function showConcatLog(){
myConsole.stop();
myConsole.start();
console.log('a');
console.log('bb');
console.dir({i:'not', j:'affected', k:'but not in step'})
console.log('ccc');
console.log([1,2,3,4,5,'6'], {x:8, y:'9'});
console.log("dddd", 1, '2', 3, myConsole.NEW_LINE);
console.log("z", myConsole.NEW_LINE, 8, '7');
console.log(new Error("error test"));
myConsole.stop();
}
myConsole.start(myConsole.ONE_LINE);
var stop_callback = 5;
function myCallback(){
console.log(stop_callback, 'Date.now()', myConsole.NEW_LINE, Date.now());
stop_callback--;
if (stop_callback>0){
window.setTimeout(myCallback, 1000);
}else{
showConcatLog();
}
}
window.setTimeout(myCallback, 1000);
You can use a spread operator to display output in the single line. The new feature of javascript ES6. see below example
for(let i = 1; i<=10; i++){
let arrData = [];
for(let j = 1; j<= 10; j++){
arrData.push(j+"X"+i+"="+(j*i));
}
console.log(...arrData);
}
That will print 1 to 10 table in single line.
// Source code for printing 2d array
window.onload = function () {
var A = [[1, 2], [3, 4]];
Print(A);
}
function Print(A) {
var rows = A.length;
var cols = A[0].length;
var line = "";
for (var r = 0; r < rows; r++) {
line = "";
for (var c = 0; c < cols; c++) {
line += A[r][c] + " ";
}
console.log(line);
}
}