Is it possible to call sub-method in javascript? - javascript

As an experiment, I am trying to build the following hierarchy of methods around Number:
Number
|
|
pad()
/\
/ \
/ \
/ \
left() right()
Precisely, I want left() and right() to be the sub-methods of pad() so that I am able to pad the number by making a call something like:
var i = 100;
i.pad().left();
Here's an experimental script that I was working on:
/*
Javascript to pad zero's to a number at the left or right.
*/
Number.prototype.pad = function()
{
Number.prototype.pad.left = function(l)
{
if(typeof l=='undefined')
l = 0;
p = this+'';
var r = l - p.length;
while((r--)>0)
p = '0'+p;
return p;
}
Number.prototype.pad.right = function(l)
{
if(typeof l=='undefined')
l = 0;
p = this+'';
var r = l - p.length;
while((r--)>0)
p = p+'0';
return p;
}
}
i = 646;
padded = i.pad.left(9); /* Possible calling format*/
alert(padded);
How is this possible in Javascript?

Issues fixed:
1) calling pad() instead of just pad
2) Pad() returns object with member left and right.
3) Most importantly, 'this' will not work inside the new functions as they are not part of number. Extracting the number outside the function.
4) p was inadvertly becoming public (window.p). Put a var in front.
See it working
Number.prototype.pad = function() {
var number = this.valueOf();
return {
left: function(l)
{
console.log(this);
if(typeof l=='undefined')
l = 0;
var p = number + '';
var r = l - p.length;
while((r--) > 0)
p = '0'+ p;
return p;
},
right: function(l)
{
if(typeof l=='undefined')
l = 0;
var p = number + '';
var r = l - p.length;
while((r--)>0)
p = p+'0';
return p;
}
}
}
i = 646;
padded = i.pad().left(9); /* Possible calling format*/
alert(padded);

Consider something simpler. You could just pass left and right as parameters to pad. For example:
Number.prototype.pad = function( l,r ) {
l = l || 0; r = r || 0;
var arr = [ this ],
i = 0, j = 0;
for ( ; i < l; ++i ) arr.unshift(0);
for ( ; j < r; ++j ) arr.push(0);
return arr.join('');
};
console.log( (12).pad(2,0) ); //=> 0012
console.log( (12).pad(0,1) ); //=> 120
console.log( (12).pad(3,2) ); //=> 0001200
Here's a shorter more functional and terse piece of code that works as well:
Number.prototype.pad = function( l,r ) {
return this.toString()
.replace( /\d+/, new Array( ++l ).join('0') +'$&'+
new Array( ++r||0 ).join('0'));
}

My version
Number.prototype.lpad = function( num ) {
var padding = new Array( num + 1 ).join("0"),
result = padding + this.toString( 10 );
return result.slice( -num );
}
Number.prototype.rpad = function( num ) {
var padding = new Array( num + 1 ).join("0"),
result = this.toString( 10 ) + padding;
return result.slice( 0, num );
}

Related

Javascript while loop (Card deck simulation)

I am having an issue with the following code that simulates a card deck.
The deck is created properly (1 array containing 4 arrays (suits) containing 13 elements each (face values)) and when I use the G.test(); function it is correctly pulling 13 random cards but then returns 39x "Empty" (A total of 52).
I hate to ask for help, but I have left the problem overnight and then some and I still cannot find the reason that this is happening. I appreciate any and all insight that can be offered.
var G = {};
G.cards = [[], [], [], []];
G.newCard = function(v) { //currently a useless function, tried a few things
return v;
};
G.deck = {
n: function() { //new deck
var x; var list = [];
list.push(G.newCard("A"));
for (x = 2; x <= 10; x += 1) {
list.push(G.newCard(x.toString()));
}
list.push(G.newCard("J"), G.newCard("Q"), G.newCard("K"));
for (x = 0; x < G.cards.length; x += 1) {
G.cards[x] = list;
}
},
d: function() { //random card - returns suit & value
var s; var c; var v; var drawn = false; var n;
s = random(0, G.cards.length);
c = random(0, G.cards[s].length);
n = 0;
while (!drawn) {
if (G.cards[s].length > 0) {
if (G.cards[s][c]) {
v = G.cards[s].splice(c, 1);
drawn = true;
} else {
c = random(0, G.cards[s].length);
}
} else {
s = (s + 1 >= G.cards.length) ? 0 : s + 1;
n += 1;
console.log(s);
if (n >= G.cards.length) {
console.log(n);
return "Empty";
}
}
}
return {s: s, v: v[0]};
},
}; //G.deck
G.test = function() {
var x; var v;
G.deck.n();
for (x = 0; x < 52; x += 1) {
v = G.deck.d();
console.log(v);
}
};
Replace
for (x = 0; x < G.cards.length; x += 1) {
G.cards[x] = list;
}
with
for (x = 0; x < G.cards.length; x += 1) {
G.cards[x] = list.slice();
}
as this prevents all elements of G.cards[x] binding to the same (single) array instance.
If all elements bind to the same instance, mutating one element equals mutating all elements. list.slice() creates a new copy of list and thus a new array instance to prevent the aforementioned issue.
I won't go through your code, but I built a code that will do what you wanted. I only built this for one deck and not multiple deck play. There are two functions, one will generate the deck, and the other will drawn cards from the deck, bases on how many hands you need and how many cards you wanted for each hand. One a card is drawn, it will not be re-drawn. I might publish a short article for how a card dealing program work or similar in the short future at http://kevinhng86.iblog.website.
function random(min, max){
return Math.floor(Math.random() * (max - min)) + min;
}
function deckGenerate(){
var output = [];
var face = {1: "A", 11: "J", 12: "Q", 13: "K"};
// Heart Space Diamond & Club;
var suit = ["H", "S", "D", "C"];
// Delimiter between card identification and suit identification.
var d = "-";
for(i = 0; i < 4; i++){
output[i] = [];
for(ind = 0; ind < 13; ind++ ){
card = (ind + 1);
output[i][ind] = (card > 10) || (card === 1)? face[card] + d + suit[i] : card.toString() + d + suit[i];
}
}
return output;
}
function randomCard(deck, hand, card){
var output = [];
var randS = 0;
var randC = 0;
if( hand * card > 52 ) throw("Too many card, I built this for one deck only");
for(i = 0; i < hand; i++){
output[i] = [];
for(ind = 0; ind < card; ind++){
randS = random(0, deck.length);
randC = random(0, deck[randS].length);
output[i][ind] = deck[randS][randC];
deck[randS].splice(randC,1);
if(deck[randS].length === 0) deck.splice(randS,1);
}
}
document.write( JSON.stringify(deck, null, 2) );
return output;
}
var deck = deckGenerate()
document.write( JSON.stringify(deck, null, 2) );
document.write("<br><br>");
var randomhands = randomCard(deck, 5, 8);
document.write("<br><br>");
document.write("<br><br>");
document.write( JSON.stringify(randomhands, null, 2) );

returning equation with all possible parenthesis combinations and the result of each

On a recent interview, I was asked to return all possible combinations of order of operations on an input string, and the result. you should return all the ways/combinations in which you can "force" operations with parenthesis. I got the result (right hand side of the equation) but got stuck on the left side. how could I have done the left side and the right hand side together? Seems like two problems in one...
//input:
console.log(diffWaysToCompute("2 * 3 - 4 * 5"));
//output:
(2*(3-(4*5))) = -34
((2*3)-(4*5)) = -14
((2*(3-4))*5) = -10
(2*((3-4)*5)) = -10
(((2*3)-4)*5) = 10
'use strict'
function getNumbersAndOperators(str) {
var arr = str.split(" ");
var operators = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] === "-" || arr[i] === "*" || arr[i] === "+") {
operators.push(arr[i]);
arr.splice(i, 1);
// console.log(operators);
}
}
return [arr, operators];
}
// console.log(getNumbersAndOperators("2 - 1 - 1"))
var diffWaysToCompute = function (input) {
// var numbers = input.split(" ");
// console.log(numbers);
// // console.log(number);
var results = compute(input);
results.sort(function (a, b) {
return a - b;
});
//put the numbers length into valid parenthesis:
var NumbersAndOperators = getNumbersAndOperators(input);
var numbers = NumbersAndOperators[0];
console.log(numbers);
var operators = NumbersAndOperators[1];
console.log(operators);
var parens = validParentheses(numbers.length);
// console.log(numbers);
console.log(operators);
// for (var i = 0; i < parens.length; i++) {
// for (var j = 0; j < parens[i].length; j++) {
// var val = parens[i][j];
// console.log(val);
// if (val === " ") {
// var num = numbers.shift();
// parens.splice(val, 0, num);
// //starting running into infinite loops and out of time.
// j--;
// }
// }
// i--;
// }
console.log(parens);
return results;
};
function validParentheses(n) {
if (n === 1) {
return ['( )'];
}
var prevParentheses = validParentheses(n - 1);
var list = {};
prevParentheses.forEach(function (item) {
list['( ' + item + ' )'] = null;
list['( )' + item] = null;
list[item + '( )'] = null;
});
console.log(Object.keys(list))
return Object.keys(list);
}
function compute(str) {
var res = [];
var i;
var j;
var k;
var left;
var right;
var string = [];
var placed = true;
if (!/[+*-]/.test(str)) { // + - *
return [parseInt(str)];
}
for (i = 0; i < str.length; i++) {
if (/\+|\-|\*/.test(str[i])) { // + - *
left = compute(str.substring(0, i));
right = compute(str.substring(i + 1, str.length));
for (j = 0; j < left.length; j++) {
for (k = 0; k < right.length; k++) {
if (str[i] === '+') {
res.push(parseInt(left[j] + right[k]));
} else if (str[i] === '-') {
// string.push("(" + str[i-2], str[i+2] + ")");
res.push(parseInt(left[j] - right[k]));
} else if (str[i] === '*') {
res.push(parseInt(left[j] * right[k]));
}
}
}
}
}
// console.log(string);
return res;
}
console.log(diffWaysToCompute("2 - 1 - 1"));
console.log(diffWaysToCompute("2 * 3 - 4 * 5"));
I never had to do such silly things, so let me try my teeth at it now.
(Caveat as always: it's highly simplified and without any checks&balances!)
The parser is the simplest thing here:
/*
Use of strings instead of ASCII codes for legibility.
I changed x - y to x + (-y) not only for convenience
but for algebraic correctness, too.
#param a array number nodes
#param o array operator nodes
*/
function parse(s,a,o){
var fnum = 0;
var uminus = false
for(var i=0;i<s.length;i++){
switch(s[i]){
case '-': uminus = true;
a.push(fnum);
o.push('+');
fnum = 0;
break;
case '+':
case '*':
case '/': if(uminus){
uminus = false;
fnum *= -1;
}
a.push(fnum);
o.push(s[i]);
fnum = 0;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': fnum = fnum * 10 + parseInt(s[i]);
break;
default: break;
}
}
//assuming symmetry
a.push(fnum);
}
The (-generation took me some time, too much time--I cheated here ;-)
/*
Found in an old notebook (ported from C)
Algo. is O(n^2) and can be done faster but I
couldn't be a...ehm, had no time, sorry.
#idx int index into individual result
#n int number of groups
#open int number of opening parentheses
#close int number of closing parentheses
#a array individual result
#all array space for all results
*/
function makeParens(idx,n,open,close,a,all){
if(close == n){
all.push(a.slice(0));
return;
} else {
if(open > close){
a[idx] = ')';
makeParens(idx+1,n,open,close+1,a,all);
}
if(open < n){
a[idx] = '(';
makeParens(idx+1,n,open+1,close,a,all);
}
}
}
And now? Yepp, that took me a while:
/*
The interesting part
Not very optimized but working
#s string the equation
#return array nicely formatted result
*/
function parenthesing(s){
var nums = [];
var ops = [];
var all = [];
var parens = [];
// parse input into numbers and operators
parse(input,nums,ops);
/*
Rules:
1) out-most parentheses must be open in direction to center
e.g.: (1+2+3), 1+(2+3), 1+(2+3)+4
but not: 1)+(2+3)+(4
so: first parenthesis on the left side must be open and
the last parenthesis on the right side must be close
2) parentheses in direct neighborhood to a number must be
open in direction to the number (multiplication is
not mutual)
e.g.: 1+(2+3)+4, but not: 1+2(+3+4)
3) parentheses in direct neighborhood to an operator must be
closed in direction to the operator (multiplication is
not mutual)
e.g.: 1+(2+3)+4, but not: 1+2(+3+)4
*/
// build combinations separately not in-line
// it's already a mess, no need to add more
makeParens(0,nums.length,0,0,[],parens);
// You may take a look at the raw material here
// console.log(parens.join("\n"));
for(var i= 0;i<parens.length;i++){
var term = [];
// work on copies to reduce pointer juggling
var _ops = ops.slice(0);
var _nums = nums.slice(0);
for(var j=0;j<parens[i].length;j++){
if(parens[i][j] === '('){
term.push("(");
// rule 3
if(parens[i][j+1] === ')'){
term.push(_nums.shift());
}
// rules 1,2
else {
term.push(_nums.shift());
term.push(_ops.shift());
}
}
if(parens[i][j] === ')'){
term.push(")");
// rules 2,3
if(parens[i][j+1] !== ')')
term.push(_ops.shift());
}
}
// some pretty printing
term = term.join("");
// eval() because I didn't want to write a parser
// but if you need one...
all.push(term + " = " + eval(term));
}
return all;
}
I'm not sure if I would get hired with that abomination. Ah, to be honest: I doubt it.
But I hope it is at least a little bit helpful.
Yikes. That was tricky. Good challenge. I'm sure this could be cut way down, but it works. I used lodash and broke the various functions down to make it more flexible. Here's a jsfiddle:
https://jsfiddle.net/mckinleymedia/3e8g22Lk/8/
Oops - had to add parseInt to the addition so it doesn't add as strings.
/*
//input:
diffWaysToCompute("2 * 3 - 4 * 5");
//output:
(2*(3-(4*5))) = -34 - 2,1,0
((2*3)-(4*5)) = -14 - 0,2,1 & 2,0,1
((2*(3-4))*5) = -10 - 1,0,2
(2*((3-4)*5)) = -10 - 1,2,0
(((2*3)-4)*5) = 10 - 0,1,2
*/
'use strict'
var diffWaysToCompute = function(str) {
var opsAvailable = ['+','-','/','*'],
numbers = [],
operators = [],
getNumbersAndOperators = function(str) {
var arr = str.split(" ");
for (var i in arr) {
if ( opsAvailable.indexOf( arr[i] ) > -1 ) {
operators.push( arr[i] );
} else {
numbers.push( arr[i] );
}
};
return;
},
permutator = function(range) {
var results = [];
function permute(arr, memo) {
var cur,
memo = memo || [];
for (var i in arr) {
cur = arr.splice(i, 1);
if (arr.length === 0) results.push(memo.concat(cur));
permute(arr.slice(), memo.concat(cur));
arr.splice(i, 0, cur[0]);
}
return results;
}
return permute(_.range(range));
},
equations = function( perms ) {
var results = [];
_.each(perms, function( perm, k ) {
results[k] = nest ( perm );
});
return results;
},
nest = function( perm ) {
var eqs = eqs || [],
ref = ref || _.range(perm.length).map(function () { return undefined }),
eq,
target = undefined;
for (var i in perm) {
var cur = perm[i],
next = perm[i] + 1,
n1 = numbers[ cur ],
n2 = numbers[ next ],
r1 = ref[ cur ],
r2 = ref[ next ];
if ( r1 !== undefined) n1 = eqs [ r1 ];
if ( r2 !== undefined) n2 = eqs [ r2 ];
var rNew;
rNew = eqs.length;
for (var x in ref ) {
if ( ( ref[ x ] !== undefined ) && ( ref[ x ] == r1 || ref[ x ] == r2 ) ) ref[ x ] = eqs.length;
};
ref[ cur ] = ref[ next ] = eqs.length;
eqs.push({
ops: operators[ cur ],
nums: [ n1, n2 ]
});
};
return eqs[ eqs.length - 1 ];
},
calculations = function ( eqs ) {
var results = []
_.each(eqs, function(equation) {
results.push(calculate( equation ));
});
return results;
},
calculate = function( eq ) {
var result = {
text: ""
};
// result.eq = eq;
result.text += "( ";
result.total = eq.nums[ 0 ];
if ( _.isObject(result.total) ) {
var result1 = calculate( result.total );
result.total = result1.total;
result.text += result1.text;
} else {
result.text += eq.nums[ 0 ];
}
_.each(eq.ops, function (op, k) {
var num = eq.nums[ k + 1 ];
result.text += " " + op + " ";
if ( _.isObject(num) ) {
var result2 = calculate( num );
num = result2.total;
result.text += result2.text;
} else {
result.text += num;
}
if ( op === '+') result.total = parseInt(result.total) + parseInt(num);
if ( op === '-') result.total = result.total - num;
if ( op === '/') result.total = result.total / num;
if ( op === '*') result.total = result.total * num;
});
result.text += " )";
return result;
},
display = function( as ) {
var target = document.getElementById('result');
target.innerHTML += '<h3 class="problem">String given: ' + str + '</h3>';
target.innerHTML += '<h4>Permutations</h4>';
_.each( as, function(a) {
target.innerHTML += '<div class="permutation">';
target.innerHTML += ' <span class="formula">' + a.text + '</span> = ';
target.innerHTML += ' <span class="total">' + a.total + '</span>';
target.innerHTML += '</div>';
});
},
perms,
eqs,
answers;
getNumbersAndOperators(str);
perms = permutator( operators.length );
eqs = equations( perms );
answers = calculations( eqs );
answers = _.uniq(answers, 'text');
display(answers);
return answers;
};
console.log(diffWaysToCompute("2 * 3 - 4 * 5"));

How do you return the resulting object in a function?

Good day, all! :)
For the past month, I have been working on a function to return 2 or more THREE.js materials in 1 function at 1 time. I've run into a small problem though. For some reason, I can't get this function to return the MeshBasicMaterial object AS WELL AS the MeshLambertMaterial data object. I KNOW my code is right because I've gone over it over 40 times already looking for errors.
Here's the WHOLE code:
/**
* A function for converting hex <-> dec w/o loss of precision.
*
* The problem is that parseInt("0x12345...") isn't precise enough to convert
* 64-bit integers correctly.
*
* Internally, this uses arrays to encode decimal digits starting with the least
* significant:
* 8 = [8]
* 16 = [6, 1]
* 1024 = [4, 2, 0, 1]
*/
// Adds two arrays for the given base (10 or 16), returning the result.
// This turns out to be the only "primitive" operation we need.
function add(x, y, base)
{
var z = [];
var n = Math.max(x.length, y.length);
var carry = 0;
var i = 0;
while (i < n || carry)
{
var xi = i < x.length ? x[i] : 0;
var yi = i < y.length ? y[i] : 0;
var zi = carry + xi + yi;
z.push(zi % base);
carry = Math.floor(zi / base);
i++;
}
return z;
}
// Returns a*x, where x is an array of decimal digits and a is an ordinary
// JavaScript number. base is the number base of the array x.
function multiplyByNumber(num, x, base)
{
if (num < 0) return null;
if (num == 0) return [];
var result = [];
var power = x;
while (true)
{
if (num & 1)
{
result = add(result, power, base);
}
num = num >> 1;
if (num === 0) break;
power = add(power, power, base);
}
return result;
}
function parseToDigitsArray(str, base)
{
var digits = str.split('');
var ary = [];
for (var i = digits.length - 1; i >= 0; i--)
{
var n = parseInt(digits[i], base);
if (isNaN(n)) return null;
ary.push(n);
}
return ary;
}
function convertBase(str, fromBase, toBase)
{
var digits = parseToDigitsArray(str, fromBase);
if (digits === null) return null;
var outArray = [];
var power = [1];
for (var i = 0; i < digits.length; i++)
{
// invariant: at this point, fromBase^i = power
if (digits[i])
{
outArray = add(outArray, multiplyByNumber(digits[i], power, toBase), toBase);
}
power = multiplyByNumber(fromBase, power, toBase);
}
var out = '';
for (var i = outArray.length - 1; i >= 0; i--)
{
out += outArray[i].toString(toBase);
}
return out;
}
function decToHex(decStr) {
var hex = convertBase(decStr, 10, 16);
return hex ? '0x' + hex : null;
}
function hexToDec(hexStr) {
if (hexStr.substring(0, 2) === '0x') hexStr = hexStr.substring(2);
hexStr = hexStr.toLowerCase();
return convertBase(hexStr, 16, 10);
}
function instr(str, val)
{
if(typeof(str) === 'string')
{
str = str.toString(str);
val = val.toString(val);
in_str = str.indexOf(val);
return in_str;
}
else
{
api_messagebox('Please use a string!');
}
return false;
}
function Get_RGBA(hexVal, getwhich)
{
hexVal = hexVal || '';
getwhich = getwhich || 0;
var commaSeperated = 0;
//if(typeof(hexVal) === 'string')
//{
// Removes the first character from the input string
if(hexVal.length === 8) { hexVal = hexVal.substring(1, hexVal.length); }
if(hexVal.length === 10) { hexVal = hexVal.substring(0, hexVal.length); }
// Now let's separate the pairs by a comma
for (var i = 0; i <= hexVal.length; i++)
{
// Iterate through each char of hexVal
// Copy each char of hexVal to commaSeperated
commaSeperated += hexVal.charAt(i);
// After each pair of characters add a comma, unless this
// is the last char
commaSeperated += (i % 2 == 1 && i != (hexVal.length - 1)) ? ',' : '';
}
// Lets now remove the 0x
if(instr(commaSeperated, '0x'))
{
commaSeperated = commaSeperated.substr(4);
}
if(instr(commaSeperated, ','))
{
// Lets now remove all "," 's
commaSeperated = commaSeperated.replace(/,/g, '');
if( getwhich < 0 ) { getwhich = 0; }
if( getwhich > 5 ) { getwhich = 5; }
alpha = [];
red = [];
green = [];
blue = [];
allcol = [];
sixcol = [];
alpha[0] = commaSeperated[0]+commaSeperated[1];
red[0] = commaSeperated[2]+commaSeperated[3];
green[0] = commaSeperated[4]+commaSeperated[5];
blue[0] = commaSeperated[6]+commaSeperated[7];
allcol[0] = alpha[0]+red[0]+green[0]+blue[0];
sixcol[0] = red[0]+green[0]+blue[0];
if( getwhich === 0 ) { fi_string = alpha[0]; }
if( getwhich === 1 ) { fi_string = red[0]; }
if( getwhich === 2 ) { fi_string = green[0]; }
if( getwhich === 3 ) { fi_string = blue[0]; }
if( getwhich === 4 ) { fi_string = allcol[0]; }
if( getwhich === 5 ) { fi_string = sixcol[0]; }
if( getwhich === 4 && fi_string.length != 10 || fi_string.length != 9 ) { getwhich = 5; }
if( getwhich === 5 && fi_string.length != 8 || fi_string.length != 7 ) { getwhich = 4; }
// Split the commaSeperated string by commas and return the array
return fi_string.toString();
}
//}
}
function isArray(myArray)
{
return myArray.constructor.toString();
//myArray.constructor.toString().indexOf("Array") > -1;
}
//EntityMaterial(0, 0, 0xFF44CFFC, 1, 0xFF000000, 4, 4, 0, 1.0, 0.8, "LambertBasicMaterial", 1)
function EntityMaterial(ptex, side, color, wire, wirecolor, col_type, col_wire_type, shading, transparent, opacity, mat_type, overdraw)
{
ptex = ptex || 0;
side = side || 0;
color = color || 0xFF006400;
wire = wire || 0;
wirecolor = wirecolor || 0xFF006400;
col_type = col_type || 4;
col_wire_type = col_wire_type || 4;
shading = shading || false;
transparent = transparent || 0.0;
opacity = opacity || 1.0;
mat_type = mat_type || "BasicMaterial";
overdraw = overdraw || true;
color = decToHex(color.toString());
wirecolor = decToHex(wirecolor.toString());
var gRGBA1 = Get_RGBA(color, col_type);
var gRGBA2 = Get_RGBA(wirecolor, col_wire_type);
var mat = 0;
if(mat_type === 'BasicMaterial')
{
this.materials = new THREE.MeshBasicMaterial
(
{
color: parseInt(gRGBA1, 16)
}
)
}
else if(mat_type === 'LambertMaterial')
{
this.materials = new THREE.MeshLambertMaterial
(
{
color: parseInt(gRGBA2, 16),
opacity: opacity,
wireframe: wire,
transparent: transparent
}
)
}
else if(mat_type === 'LambertBasicMaterial')
{
//new empty array.. could also be written as this.materials = new Array();
this.materials = [];
var mats = this.materials;
var basicMat = new THREE.MeshBasicMaterial( { color: parseInt(gRGBA1, 16) } );
var lambertMat = new THREE.MeshLambertMaterial( { color: parseInt(gRGBA2, 16), opacity: opacity, wireframe: wire, transparent: transparent } );
mats.push(basicMat);
mats.push(lambertMat);
api_messagebox(mats);
return mats;
}
}
Thank you so much!
Sincerely,
~Mythros
Right, I finally got around to trying it out and it all runs well for me.
To make sure we don't have any differences in environments take a look at the fiddle I made and let me know if it works for you as expected or if there's any other problems you need help with:
JSFiddle of original code
Small changes:
commented out the
api_messagebox(mats)
as it's undefined.
added lots of log statements so check out the web console.
Edit
I fixed the color problem by using THree.js' Color object as follows:
var color = new THREE.Color("rgb(0,0,255)");
But you may be doing this somewhere as the GET_RGBA function you are calling seems to be missing from the code you gave me.
As to making it wiremesh, I checked the Lambert object and it definitely had wiremesh = 1 set.
Make sure that the wire var you're passing is actually set to true, I set it explicitly in this updated fiddle

Function to solve cubic equation analytically

I need to solve a cubic equation (ax^3 + bx^2 + c*x + d = 0) analytically and in real numbers, preferably in pure javascript (no libs). As there could be 1 to 3 roots, I think an array of numbers is a reasonable result type.
P.S. Provided my own solution below, hope it'll be useful.
Here you go. Includes handling degenerate cases. Main algorithm is mostly from wikipedia article.
function cuberoot(x) {
var y = Math.pow(Math.abs(x), 1/3);
return x < 0 ? -y : y;
}
function solveCubic(a, b, c, d) {
if (Math.abs(a) < 1e-8) { // Quadratic case, ax^2+bx+c=0
a = b; b = c; c = d;
if (Math.abs(a) < 1e-8) { // Linear case, ax+b=0
a = b; b = c;
if (Math.abs(a) < 1e-8) // Degenerate case
return [];
return [-b/a];
}
var D = b*b - 4*a*c;
if (Math.abs(D) < 1e-8)
return [-b/(2*a)];
else if (D > 0)
return [(-b+Math.sqrt(D))/(2*a), (-b-Math.sqrt(D))/(2*a)];
return [];
}
// Convert to depressed cubic t^3+pt+q = 0 (subst x = t - b/3a)
var p = (3*a*c - b*b)/(3*a*a);
var q = (2*b*b*b - 9*a*b*c + 27*a*a*d)/(27*a*a*a);
var roots;
if (Math.abs(p) < 1e-8) { // p = 0 -> t^3 = -q -> t = -q^1/3
roots = [cuberoot(-q)];
} else if (Math.abs(q) < 1e-8) { // q = 0 -> t^3 + pt = 0 -> t(t^2+p)=0
roots = [0].concat(p < 0 ? [Math.sqrt(-p), -Math.sqrt(-p)] : []);
} else {
var D = q*q/4 + p*p*p/27;
if (Math.abs(D) < 1e-8) { // D = 0 -> two roots
roots = [-1.5*q/p, 3*q/p];
} else if (D > 0) { // Only one real root
var u = cuberoot(-q/2 - Math.sqrt(D));
roots = [u - p/(3*u)];
} else { // D < 0, three roots, but needs to use complex numbers/trigonometric solution
var u = 2*Math.sqrt(-p/3);
var t = Math.acos(3*q/p/u)/3; // D < 0 implies p < 0 and acos argument in [-1..1]
var k = 2*Math.PI/3;
roots = [u*Math.cos(t), u*Math.cos(t-k), u*Math.cos(t-2*k)];
}
}
// Convert back from depressed cubic
for (var i = 0; i < roots.length; i++)
roots[i] -= b/(3*a);
return roots;
}

Compare Strings Javascript Return %of Likely

I am looking for a JavaScript function that can compare two strings and return the likeliness that they are alike. I have looked at soundex but that's not really great for multi-word strings or non-names. I am looking for a function like:
function compare(strA,strB){
}
compare("Apples","apple") = Some X Percentage.
The function would work with all types of strings, including numbers, multi-word values, and names. Perhaps there's a simple algorithm I could use?
Ultimately none of these served my purpose so I used this:
function compare(c, u) {
var incept = false;
var ca = c.split(",");
u = clean(u);
//ca = correct answer array (Collection of all correct answer)
//caa = a single correct answer word array (collection of words of a single correct answer)
//u = array of user answer words cleaned using custom clean function
for (var z = 0; z < ca.length; z++) {
caa = $.trim(ca[z]).split(" ");
var pc = 0;
for (var x = 0; x < caa.length; x++) {
for (var y = 0; y < u.length; y++) {
if (soundex(u[y]) != null && soundex(caa[x]) != null) {
if (soundex(u[y]) == soundex(caa[x])) {
pc = pc + 1;
}
}
else {
if (u[y].indexOf(caa[x]) > -1) {
pc = pc + 1;
}
}
}
}
if ((pc / caa.length) > 0.5) {
return true;
}
}
return false;
}
// create object listing the SOUNDEX values for each letter
// -1 indicates that the letter is not coded, but is used for coding
// 0 indicates that the letter is omitted for modern census archives
// but acts like -1 for older census archives
// 1 is for BFPV
// 2 is for CGJKQSXZ
// 3 is for DT
// 4 is for L
// 5 is for MN my home state
// 6 is for R
function makesoundex() {
this.a = -1
this.b = 1
this.c = 2
this.d = 3
this.e = -1
this.f = 1
this.g = 2
this.h = 0
this.i = -1
this.j = 2
this.k = 2
this.l = 4
this.m = 5
this.n = 5
this.o = -1
this.p = 1
this.q = 2
this.r = 6
this.s = 2
this.t = 3
this.u = -1
this.v = 1
this.w = 0
this.x = 2
this.y = -1
this.z = 2
}
var sndx = new makesoundex()
// check to see that the input is valid
function isSurname(name) {
if (name == "" || name == null) {
return false
} else {
for (var i = 0; i < name.length; i++) {
var letter = name.charAt(i)
if (!(letter >= 'a' && letter <= 'z' || letter >= 'A' && letter <= 'Z')) {
return false
}
}
}
return true
}
// Collapse out directly adjacent sounds
// 1. Assume that surname.length>=1
// 2. Assume that surname contains only lowercase letters
function collapse(surname) {
if (surname.length == 1) {
return surname
}
var right = collapse(surname.substring(1, surname.length))
if (sndx[surname.charAt(0)] == sndx[right.charAt(0)]) {
return surname.charAt(0) + right.substring(1, right.length)
}
return surname.charAt(0) + right
}
// Collapse out directly adjacent sounds using the new National Archives method
// 1. Assume that surname.length>=1
// 2. Assume that surname contains only lowercase letters
// 3. H and W are completely ignored
function omit(surname) {
if (surname.length == 1) {
return surname
}
var right = omit(surname.substring(1, surname.length))
if (!sndx[right.charAt(0)]) {
return surname.charAt(0) + right.substring(1, right.length)
}
return surname.charAt(0) + right
}
// Output the coded sequence
function output_sequence(seq) {
var output = seq.charAt(0).toUpperCase() // Retain first letter
output += "-" // Separate letter with a dash
var stage2 = seq.substring(1, seq.length)
var count = 0
for (var i = 0; i < stage2.length && count < 3; i++) {
if (sndx[stage2.charAt(i)] > 0) {
output += sndx[stage2.charAt(i)]
count++
}
}
for (; count < 3; count++) {
output += "0"
}
return output
}
// Compute the SOUNDEX code for the surname
function soundex(value) {
if (!isSurname(value)) {
return null
}
var stage1 = collapse(value.toLowerCase())
//form.result.value=output_sequence(stage1);
var stage1 = omit(value.toLowerCase())
var stage2 = collapse(stage1)
return output_sequence(stage2);
}
function clean(u) {
var u = u.replace(/\,/g, "");
u = u.toLowerCase().split(" ");
var cw = ["ARRAY OF WORDS TO BE EXCLUDED FROM COMPARISON"];
var n = [];
for (var y = 0; y < u.length; y++) {
var test = false;
for (var z = 0; z < cw.length; z++) {
if (u[y] != "" && u[y] != cw[z]) {
test = true;
break;
}
}
if (test) {
//Don't use & or $ in comparison
var val = u[y].replace("$", "").replace("&", "");
n.push(val);
}
}
return n;
}
Here's an answer based on Levenshtein distance https://en.wikipedia.org/wiki/Levenshtein_distance
function similarity(s1, s2) {
var longer = s1;
var shorter = s2;
if (s1.length < s2.length) {
longer = s2;
shorter = s1;
}
var longerLength = longer.length;
if (longerLength == 0) {
return 1.0;
}
return (longerLength - editDistance(longer, shorter)) / parseFloat(longerLength);
}
For calculating edit distance
function editDistance(s1, s2) {
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
var costs = new Array();
for (var i = 0; i <= s1.length; i++) {
var lastValue = i;
for (var j = 0; j <= s2.length; j++) {
if (i == 0)
costs[j] = j;
else {
if (j > 0) {
var newValue = costs[j - 1];
if (s1.charAt(i - 1) != s2.charAt(j - 1))
newValue = Math.min(Math.min(newValue, lastValue),
costs[j]) + 1;
costs[j - 1] = lastValue;
lastValue = newValue;
}
}
}
if (i > 0)
costs[s2.length] = lastValue;
}
return costs[s2.length];
}
Usage
similarity('Stack Overflow','Stack Ovrflw')
returns 0.8571428571428571
You can play with it below:
function checkSimilarity(){
var str1 = document.getElementById("lhsInput").value;
var str2 = document.getElementById("rhsInput").value;
document.getElementById("output").innerHTML = similarity(str1, str2);
}
function similarity(s1, s2) {
var longer = s1;
var shorter = s2;
if (s1.length < s2.length) {
longer = s2;
shorter = s1;
}
var longerLength = longer.length;
if (longerLength == 0) {
return 1.0;
}
return (longerLength - editDistance(longer, shorter)) / parseFloat(longerLength);
}
function editDistance(s1, s2) {
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
var costs = new Array();
for (var i = 0; i <= s1.length; i++) {
var lastValue = i;
for (var j = 0; j <= s2.length; j++) {
if (i == 0)
costs[j] = j;
else {
if (j > 0) {
var newValue = costs[j - 1];
if (s1.charAt(i - 1) != s2.charAt(j - 1))
newValue = Math.min(Math.min(newValue, lastValue),
costs[j]) + 1;
costs[j - 1] = lastValue;
lastValue = newValue;
}
}
}
if (i > 0)
costs[s2.length] = lastValue;
}
return costs[s2.length];
}
<div><label for="lhsInput">String 1:</label> <input type="text" id="lhsInput" oninput="checkSimilarity()" /></div>
<div><label for="rhsInput">String 2:</label> <input type="text" id="rhsInput" oninput="checkSimilarity()" /></div>
<div>Match: <span id="output">No Input</span></div>
Using this library for string similarity worked like a charm for me!
Here's the Example -
var similarity = stringSimilarity.compareTwoStrings("Apples","apple"); // => 0.88
Here is a very simple function that does a comparison and returns a percentage based on equivalency. While it has not been tested for all possible scenarios, it may help you get started.
function similar(a,b) {
var equivalency = 0;
var minLength = (a.length > b.length) ? b.length : a.length;
var maxLength = (a.length < b.length) ? b.length : a.length;
for(var i = 0; i < minLength; i++) {
if(a[i] == b[i]) {
equivalency++;
}
}
var weight = equivalency / maxLength;
return (weight * 100) + "%";
}
alert(similar("test","tes")); // 75%
alert(similar("test","test")); // 100%
alert(similar("test","testt")); // 80%
alert(similar("test","tess")); // 75%
To Find degree of similarity between two strings; we can use more than one or two methods but I am mostly inclined towards the usage of 'Dice's Coefficient' . which is better! well in my knowledge than using 'Levenshtein distance'
Using this 'string-similarity' package from npm you will be able to work on what I said above.
some easy usage examples are
var stringSimilarity = require('string-similarity');
var similarity = stringSimilarity.compareTwoStrings('healed', 'sealed');
var matches = stringSimilarity.findBestMatch('healed', ['edward', 'sealed', 'theatre']);
for more please visit the link given above. Thankyou.
Just one I quickly wrote that might be good enough for your purposes:
function Compare(strA,strB){
for(var result = 0, i = strA.length; i--;){
if(typeof strB[i] == 'undefined' || strA[i] == strB[i]);
else if(strA[i].toLowerCase() == strB[i].toLowerCase())
result++;
else
result += 4;
}
return 1 - (result + 4*Math.abs(strA.length - strB.length))/(2*(strA.length+strB.length));
}
This weighs characters that are the same but different case 1 quarter as heavily as characters that are completely different or missing. It returns a number between 0 and 1, 1 meaning the strings are identical. 0 meaning they have no similarities. Examples:
Compare("Apple", "Apple") // 1
Compare("Apples", "Apple") // 0.8181818181818181
Compare("Apples", "apple") // 0.7727272727272727
Compare("a", "A") // 0.75
Compare("Apples", "appppp") // 0.45833333333333337
Compare("a", "b") // 0
How about function similar_text from PHP.js library?
It is based on a PHP function with the same name.
function similar_text (first, second) {
// Calculates the similarity between two strings
// discuss at: http://phpjs.org/functions/similar_text
if (first === null || second === null || typeof first === 'undefined' || typeof second === 'undefined') {
return 0;
}
first += '';
second += '';
var pos1 = 0,
pos2 = 0,
max = 0,
firstLength = first.length,
secondLength = second.length,
p, q, l, sum;
max = 0;
for (p = 0; p < firstLength; p++) {
for (q = 0; q < secondLength; q++) {
for (l = 0;
(p + l < firstLength) && (q + l < secondLength) && (first.charAt(p + l) === second.charAt(q + l)); l++);
if (l > max) {
max = l;
pos1 = p;
pos2 = q;
}
}
}
sum = max;
if (sum) {
if (pos1 && pos2) {
sum += this.similar_text(first.substr(0, pos2), second.substr(0, pos2));
}
if ((pos1 + max < firstLength) && (pos2 + max < secondLength)) {
sum += this.similar_text(first.substr(pos1 + max, firstLength - pos1 - max), second.substr(pos2 + max, secondLength - pos2 - max));
}
}
return sum;
}
fuzzyset - A fuzzy string set for javascript.
fuzzyset is a data structure that performs something akin to fulltext search against data to determine likely mispellings and approximate string matching. Note that this is a javascript port of a python library.
To some extent, I like the ideas of Dice's coefficient embedded in the string-similarity module. But I feel that considering the bigrams only and not taking into account their multiplicities is missing some important data. Below is a version that also handles multiplicities, and I think is a simpler implementation overall. I don't try to use their API, offering only a function which compares two strings after some manipulation (removing non-alphanumeric characters, lower-casing everything, and compressing but not removing whitespace), built atop one which compares them without that manipulation. It would be easy enough to wrap this back in their API, but I see little need.
const stringSimilarity = (a, b) =>
_stringSimilarity (prep (a), prep (b))
const _stringSimilarity = (a, b) => {
const bg1 = bigrams (a)
const bg2 = bigrams (b)
const c1 = count (bg1)
const c2 = count (bg2)
const combined = uniq ([... bg1, ... bg2])
.reduce ((t, k) => t + (Math .min (c1 [k] || 0, c2 [k] || 0)), 0)
return 2 * combined / (bg1 .length + bg2 .length)
}
const prep = (str) => // TODO: unicode support?
str .toLowerCase () .replace (/[^\w\s]/g, ' ') .replace (/\s+/g, ' ')
const bigrams = (str) =>
[...str] .slice (0, -1) .map ((c, i) => c + str [i + 1])
const count = (xs) =>
xs .reduce ((a, x) => ((a [x] = (a [x] || 0) + 1), a), {})
const uniq = (xs) =>
[... new Set (xs)]
console .log (stringSimilarity (
'foobar',
'Foobar'
)) //=> 1
console .log (stringSimilarity (
"healed",
"sealed"
))//=> 0.8
console .log (stringSimilarity (
"Olive-green table for sale, in extremely good condition.",
"For sale: table in very good condition, olive green in colour."
)) //=> 0.7787610619469026
console .log (stringSimilarity (
"Olive-green table for sale, in extremely good condition.",
"For sale: green Subaru Impreza, 210,000 miles"
)) //=> 0.38636363636363635
console .log (stringSimilarity (
"Olive-green table for sale, in extremely good condition.",
"Wanted: mountain bike with at least 21 gears."
)) //=> 0.1702127659574468
console .log (stringSimilarity (
"The rain in Spain falls mainly on the plain.",
"The run in Spun falls munly on the plun.",
)) //=> 0.7560975609756098
console .log (stringSimilarity (
"Fa la la la la, la la la la",
"Fa la la la la, la la",
)) //=> 0.8636363636363636
console .log (stringSimilarity (
"car crash",
"carcrash",
)) //=> 0.8
console .log (stringSimilarity (
"Now is the time for all good men to come to the aid of their party.",
"Huh?",
)) //=> 0
.as-console-wrapper {max-height: 100% !important; top: 0}
Some of the test cases are from string-similarity, others are my own. They show some significant differences from that package, but nothing untoward. The only one I would call out is the difference between "car crash" and "carcrash", which string-similarity sees as identical and I report with a similarity of 0.8. My version finds more similarity in all the olive-green test-cases than does string-similarity, but as these are in any case fairly arbitrary numbers, I'm not sure how much difference it makes; they certainly position them in the same relative order.
string-similarity lib vs Top answer (by #overloard1234) performance comparation you can find below
Based on #Tushar Walzade's advice to use string-similarity library, you can find, that for example
stringSimilatityLib.findBestMatch('KIA','Kia').bestMatch.rating
will return 0.0
So, looks like better to compare it in lowerCase.
Better base usage (for arrays) :
findBestMatch(str, strArr) {
const lowerCaseArr = strArr.map(element => element.toLowerCase());//creating lower case array
const match = stringSimilatityLib.findBestMatch(str.toLowerCase(), lowerCaseArr).bestMatch; //trying to find bestMatch
if (match.rating > 0) {
const foundIndex = lowerCaseArr.findIndex(x => x === match.target); //finding the index of found best case
return strArr[foundIndex]; //returning initial value from array
}
return null;
},
Performance
Also, i compared top answer here (made by #overloard1234) and string-similarity lib (v4.0.4).
The results you can find here : https://jsbench.me/szkzojoskq/1
Result : string-similarity is ~ twice faster
Just for fun : v2.0 of string-similarity library slower, than latest 4.0.4 about 2.2 times. So update it, if you are still using < 3.0 :)
const str1 = " pARTH PARmar r ";
const str2 = " parmar r par ";
function calculateSimilarity(str1 = "", str2 = "") {
let longer = str1.trim();
let shorter = str2.trim();
let a1 = longer.toLowerCase().split(" ");
let b1 = shorter.toLowerCase().split(" ");
let result = a1.every((aa, i) => aa[0] === b1[i][0]);
if (longer.length < shorter.length) [longer,shorter] = [shorter,longer];
var arr = [];
let count = 0;
for(var i = 0;i<longer.length;i++){
if(shorter && shorter.includes(longer[i])) {
shorter = shorter.replace(longer[i],"")
count++
};
}
return {
score : (count*100)/longer.length,
result
}
}
console.log(calculateSimilarity(str1, str2));
I used #overlord1234 function, but corrected ь: '', cuz English words don't have this letter, and next need return a[char] ?? char instead of return a[char] || char

Categories

Resources