Why can't I assign new value to variable inside a block? - javascript

Below I have two examples of code. They are the same except I change the value of w at the beginning. In either example, m has a value. All I'm trying to do is set x = m. Why can I do this in the first but not the second? I'm testing this in the console in Chrome (68.0.3440.84)
This works (m = 100| x = 100)
var c = [],
w="word",
x = 0;
for (l=0; l<w.length; l++){
c.push(w.charCodeAt(l));
}
for (i in c) {
if (c.length > 0) {
var m = c[1];
if (m > Math.min(m, c[i])) {
m = Math.min(m, c[i]);
x = m;
console.log(x);
}
}
}
This does not work (m = 97| x = 0):
var c = [],
w="cancel",
x = 0;
for (l=0; l<w.length; l++){
c.push(w.charCodeAt(l));
}
for (i in c) {
if (c.length > 0) {
var m = c[1];
if (m > Math.min(m, c[i])) {
m = Math.min(m, c[i]);
x = m; //why cant I set this?
console.log(x);
}
}
}
There is more I want to do but in my process of figuring out this learning problem I have I have been unable to set this variable x reliably and I'm trying to figure out why.

It is because if (m > Math.min(m, c[i])) condition is never met. In your example both m and Math.min(m, c[i]) have the same value. Replacing > with >= seems to be fixing your issue. Or moving console.log outside if statement - depending on what you're actually trying to achieve.
var c = [],
w = "cancel",
x = 0;
for (l = 0; l < w.length; l++) {
c.push(w.charCodeAt(l));
}
for (i in c) {
if (c.length > 0) {
var m = c[1];
if (m >= Math.min(m, c[i])) { // because m > Math.min(m, c[i]) would return false
m = Math.min(m, c[i]);
x = m
console.log(x);
}
}
}

Related

Prime Factorization Giving Repeats in JS

var userNumber = parseInt(prompt("What number would you like to have factored?"));
var factoring = function(n) {
var m = n;
var o = n;
for(i = 2; i < n/2; i++) {
if (m % i === 0 && o % i === 0) {
var p = 0;
while (n % i === 0) {
n = n / i;
p++;
}
n = m;
o = o / i;
if (p > 1) {
console.log(i + "^" + p);
}
else {
console.log(i);
}
}
else {}
}
};
factoring(userNumber);
When I feed the above code an input that's large and relatively very composite, it gives wrong answers. 900, for example gives:
2^2
3^2
5^2
6^2
The first three rows are accurate, but the 6^2 is just a repeat of the 2 and the 3. How do I make the 6^2 not show, as well as solving other similar problems like the extra 25 given when you input 1000?
P.S. I am aware that this code takes more work than is necessary, but I would still rather make it work more or less as is than replace it with some other method entirely.
You are resetting n to its original value by doing n=m;. This is the reason, why you get non-prime factors. Also, you don't need o. Also, you need to run your outer loop till m/2 + 1, not just till m/2. See the corrected version below.
var userNumber = parseInt(prompt("What number would you like to have factored?"));
var factoring = function(n) {
var m = n;
var o = n;
for(i = 2; i < m/2 + 1; i++) {
if (n % i === 0) {
var p = 0;
while (n % i === 0) {
n = n / i;
p++;
}
if (p > 1) {
console.log(i + "^" + p);
}
else {
console.log(i);
}
}
else {}
}
};
factoring(userNumber);

An algorithm to translate relative coordinates to absolute coordinates

Are there any math geniuses out there that are aware of or able to devise an algorithm that will translate relative coordinates into absolute coordinates?
I created an SVG (codepen) with loads and loads and loads of paths (roughly 600) and other SVG elements, a great number of which (roughly 100) have CSS transformations applied to them. Unfortunately, I created it using Chrome and never bothered to check Firefox or other browsers.
On Firefox, none of them work correctly because the transforms are happening in relation to either the viewport or the SVG viewbox; I'm not entirely sure which one since I set the same values for the viewBox and the width and height. Microsoft Edge is another beast. It seems as if Edge doesn't even support CSS transforms applied to SVGs at the moment.
I've come across other questions (and responses) which state an adequate cross browser solution is to use "absolute" coordinates (or coordinates relative to the viewBox).
So again, is there an easy way to translate such coordinates accordingly?
I ended up writing a script that provides me with the necessary adjustments, which can be seen below!
for (i = 0; i < groundDoorIds.length; i++) {
var a = groundDoorIds[i].replace('g-o-', '');
console.log(a);
var b = document.getElementById(groundDoorIds[i]);
var c = b.getAttribute('d');
var d = c.substr(2, 11);
var e;
if (d.indexOf('h') < 0) {
if (d.indexOf('H') < 0) {
if (d.indexOf('v') < 0) {
e = d.indexOf('V');
} else {
e = d.indexOf('v');
}
} else {
e = d.indexOf('H');
}
} else {
e = d.indexOf('h');
}
var f = d.slice(0, e);
var g = f.indexOf(',');
var h = f.slice(0, g);
var j = f.slice(g + 1);
var k;
var l;
if (a.indexOf('door-right-top') > 0 || a.indexOf('door-right-bottom') > 0) {
k = Number(h) + 0.5;
l = Number(j);
} else if (a.indexOf('door-left-top') > 0 || a.indexOf('door-left-bottom') > 0) {
k = Number(h) - 0.5;
l = Number(j);
} else if (a.indexOf('door-bottom-left') > 0 || a.indexOf('door-bottom-right') > 0) {
k = Number(h);
l = Number(j) + 0.5;
} else if (a.indexOf('door-top-left') > 0 || a.indexOf('door-top-right') > 0) {
k = Number(h);
l = Number(j) - 0.5;
}
console.log('style="transform-origin:' + k + 'px ' + l + 'px;"')
console.log(`
`)
}
// which logs to the console the following information for each door
//
// construction-shop-stairwell-c-door-right-top [part of id of ele]
// style="transform-origin:92.5px 11px;" [new "absolute" coords]
For those who were confused by my question, below is basically what I was asking for.
for (i = 0; i < groundDoorIds.length; i++) {
var a = groundDoorIds[i].replace('g-o-', '');
console.log(a);
var b = document.getElementById(groundDoorIds[i]);
var c = b.getAttribute('d');
var d = c.substr(2, 11);
var e;
if (d.indexOf('h') < 0) {
if (d.indexOf('H') < 0) {
if (d.indexOf('v') < 0) {
e = d.indexOf('V');
} else {
e = d.indexOf('v');
}
} else {
e = d.indexOf('H');
}
} else {
e = d.indexOf('h');
}
var f = d.slice(0, e);
var g = f.indexOf(',');
var h = f.slice(0, g);
var j = f.slice(g + 1);
var k;
var l;
if (a.indexOf('door-right-top') > 0 || a.indexOf('door-right-bottom') > 0) {
k = Number(h) + 0.5;
l = Number(j);
} else if (a.indexOf('door-left-top') > 0 || a.indexOf('door-left-bottom') > 0) {
k = Number(h) - 0.5;
l = Number(j);
} else if (a.indexOf('door-bottom-left') > 0 || a.indexOf('door-bottom-right') > 0) {
k = Number(h);
l = Number(j) + 0.5;
} else if (a.indexOf('door-top-left') > 0 || a.indexOf('door-top-right') > 0) {
k = Number(h);
l = Number(j) - 0.5;
}
console.log('style="transform-origin:' + k + 'px ' + l + 'px;"')
console.log(`
`)
}
...which logs to console the following information for each door.
construction-shop-stairwell-c-door-right-top // part of id of ele
style="transform-origin:92.5px 11px;" // new "absolute" coords

How to add two big numbers in javascript?

I have two text boxes. Each will take input up to thousand digits.
Now i want to add these two numbers. My question is what data type should i use to store the result?
I have tried this:
<script>
var x = 'Thousand digit of number'
var y = 'Thousand digit of number'
var z = x + y
</script>
but i am getting result in exponential form. How to store the result and display it?
Yet another solution, because it's faster and cleaner.
function add(A, B) {
const AL = A.length
const BL = B.length
const ML = Math.max(AL, BL)
let carry = 0, sum = ''
for (let i = 1; i <= ML; i++) {
let a = +A.charAt(AL - i)
let b = +B.charAt(BL - i)
let t = carry + a + b
carry = t/10 |0
t %= 10
sum = (i === ML && carry)
? carry*10 + t + sum
: t + sum
}
return sum
}
> add(
'9999999999999999999999999999999999999999999999999999999999999999999999999999',
'999999999999999999999999999999999999999'
)
> "10000000000000000000000000000000000000999999999999999999999999999999999999998"
Use BigInt as described here: https://stackoverflow.com/a/56370672/641913
const z = BigInt(x) + BigInt(y);
console.log(z.toString());
Here is another solution not so different from others you can find in the internet (consider that it doesn't work with negative numbers!):
function sums(arg1, arg2) {
var sum = "";
var r = 0;
var a1, a2, i;
// Pick the shortest string as first parameter and the longest as second parameter in my algorithm
if (arg1.length < arg2.length) {
a1 = arg1;
a2 = arg2;
}
else {
a1 = arg2;
a2 = arg1;
}
a1 = a1.split("").reverse();
a2 = a2.split("").reverse();
// Sum a1 and a2 digits
for (i = 0; i < a2.length; i++) {
var t = ((i < a1.length) ? parseInt(a1[i]) : 0) + parseInt(a2[i]) + r;
sum += t % 10;
r = t < 10 ? 0 : Math.floor(t / 10);
}
// Append the last remain
if (r > 0)
sum += r;
sum = sum.split("").reverse();
// Trim the leading "0"
while (sum[0] == "0")
sum.shift();
return sum.length > 0 ? sum.join("") : "0";
}
// Test
function testEquals(expected, actual) {
if (expected == actual)
console.log("OK: " + expected);
else
console.error("ERROR: " + expected + " != " + actual);
}
testEquals("100", sums("99", "1"));
testEquals("100", sums("00099", "0001"));
testEquals("10000000000", sums("9999999999", "1"));
testEquals("10000010101", sums("9999999999", "10102"));
testEquals("0", sums("0", "0"));
testEquals("1", sums("0", "1"));
testEquals("9", sums("8", "1"));
testEquals("9", sums("1", "8"));
testEquals("10000000000000000000000000000000000000000", sums("9999999999999999999999999999999999999999", "1"));
Input the numbers as string and add each characters each other as array something like this:
function add() {
document.getElementById("demo").innerHTML = "";
var x = document.getElementById("txt1").value;
var y = document.getElementById("txt2").value;
var len;
var lenx = x.length;
var leny = y.length;
var x1,y1,rem,div=0;
if(lenx>leny) len = lenx; else len = leny;
for(var i=0;i<len;i++){
if(i>=lenx) x1 = 0;
else x1 = parseInt(x[lenx-i-1]);
if(i>=leny) y1 = 0;
else y1 = parseInt(y[leny-i-1]);
rem = (x1+y1+div)%10;
div = Math.floor((x1 + y1+div)/10);
document.getElementById("demo").innerHTML = rem + document.getElementById("demo").innerHTML;
}
if(div>0){
document.getElementById("demo").innerHTML = div + document.getElementById("demo").innerHTML;
}
}
Here the code: https://jsfiddle.net/mtsL1k2x/5/
Note: this is only for natural numbers. You can modify depending on your inputs
Either use a big number library like https://mathjs.org/docs/datatypes/bignumbers.html , or you can use something lighter weight (but easy to understand) like http://www.discoversdk.com/knowledge-base/arbitrary-length-integer-addition-in-javascript
Well, if you want to do this without using BigInt or any third-party Library, then I don't think you need to convert to an array, you can use the charAt() function to add the individual characters at each point in the string. You would have to use the for loop starting from its maximum value and reducing till its lowest. The code snippet is below;
function add(a, b) {
let sum='';
let z,x;
let r=0;
if (a.length>=b.length){
z=a;
x=b;
}
else{
z=b;
x=a;
};
let p=x.length;
for (let i=z.length;i>0;i--){
let t=((p>0)?parseInt(x.charAt(p-1)):0)+parseInt(z.charAt(i-1))+r;
sum=(t%10)+sum;
r=t<10?0:Math.floor(t/10);
p=p-1;
};
if (r>0){sum=r+sum};
return sum;
};
function add(a, b) {
a = a.split("").reverse();
b = b.split("").reverse();
let maxLen=Math.max(a.length, b.length);
let sum = [];
let remainder = 0;
for (let i = 0; i < maxLen; i++) {
let x = parseInt(a[i]) ? parseInt(a[i]) : 0;
let y = parseInt(b[i]) ? parseInt(b[i]) : 0;
let digit = (x + y + remainder) % 10;
remainder = Math.floor((x + y + remainder) / 10);
sum.unshift(digit);
}
if (remainder) {sum.unshift(remainder)}
return sum.join("");
}
function add(x, y) {
//this function adds two extremely large numbers, negative and/or positive
var temp, borrow=false, bothNeg=false, oneNeg=false, neg=false;
if (x < 0 && y < 0) { bothNeg = true; x = -x; y = -y; }
else if (x < 0 || y < 0) {
oneNeg = true;
if (Math.abs(x) == Math.abs(y)) { x = 0; y = 0; }
else if (x < 0 && Math.abs(x) > Math.abs(y)) { neg = true; x = -x; y = -y; }
else if (x < 0 && Math.abs(x) < Math.abs(y)) { temp = y; y = x; x = temp; }
else if (y < 0 && Math.abs(x) < Math.abs(y)) { neg = true; temp = y; y = -x; x = -temp; }
}
x = parseInt(x*1000000000/10).toString();
y = parseInt(y*1000000000/10).toString();
var lenx=x.length, leny=y.length, len=(lenx>leny)?lenx:leny, sum="", div=0, x1, y1, rem;
for (var i = 0; i < len; i++) {
x1 = (i >= lenx) ? 0 : parseInt(x[lenx-i-1]);
y1 = (i >= leny) ? 0 : parseInt(y[leny-i-1]);
y1 = (isNaN(y1)) ? 0 : y1;
if (oneNeg) y1 = -y1;
if (borrow) x1 = x1 - 1;
if (y < 0 && x1 > 0 && Math.abs(x1) >= Math.abs(y1)) { borrow=false; div=0; }
if (y < 0 && y1 <= 0 && (x1 < 0 || Math.abs(x1) < Math.abs(y1))) { borrow=true; rem=(x1+y1+div+10)%10; div=10; }
else { rem=(x1+y1+div)%10; div=Math.floor((x1+y1+div)/10); }
sum = Math.abs(rem).toString() + sum;
}
if (div > 0) sum = div.toString() + sum;
sum = parseFloat(sum*10/1000000000);
if (bothNeg || neg) sum = -sum;
return sum;
}
<body>
<p>Click the button to calculate x.</p>
<button onclick="myFunction()">Try it</button>
<br/>
<br/>Enter first number:
<input type="text" id="txt1" name="text1">Enter second number:
<input type="text" id="txt2" name="text2">
<p id="demo"></p>
<script>
function myFunction() {
var y = document.getElementById("txt1").value;
var z = document.getElementById("txt2").value;
var x = +y + +z;
document.getElementById("demo").innerHTML = x;
}
</script>
https://jsfiddle.net/Sanjeevgaut/mtsL1k2x/

Sort an array by the "Levenshtein Distance" with best performance in Javascript

So I have a random javascript array of names...
[#larry,#nicholas,#notch] etc.
They all start with the # symbol. I'd like to sort them by the Levenshtein Distance so that the the ones at the top of the list are closest to the search term. At the moment, I have some javascript that uses jQuery's .grep() on it using javascript .match() method around the entered search term on key press:
(code edited since first publish)
limitArr = $.grep(imTheCallback, function(n){
return n.match(searchy.toLowerCase())
});
modArr = limitArr.sort(levenshtein(searchy.toLowerCase(), 50))
if (modArr[0].substr(0, 1) == '#') {
if (atRes.childred('div').length < 6) {
modArr.forEach(function(i){
atRes.append('<div class="oneResult">' + i + '</div>');
});
}
} else if (modArr[0].substr(0, 1) == '#') {
if (tagRes.children('div').length < 6) {
modArr.forEach(function(i){
tagRes.append('<div class="oneResult">' + i + '</div>');
});
}
}
$('.oneResult:first-child').addClass('active');
$('.oneResult').click(function(){
window.location.href = 'http://hashtag.ly/' + $(this).html();
});
It also has some if statements detecting if the array contains hashtags (#) or mentions (#). Ignore that. The imTheCallback is the array of names, either hashtags or mentions, then modArr is the array sorted. Then the .atResults and .tagResults elements are the elements that it appends each time in the array to, this forms a list of names based on the entered search terms.
I also have the Levenshtein Distance algorithm:
var levenshtein = function(min, split) {
// Levenshtein Algorithm Revisited - WebReflection
try {
split = !("0")[0]
} catch(i) {
split = true
};
return function(a, b) {
if (a == b)
return 0;
if (!a.length || !b.length)
return b.length || a.length;
if (split) {
a = a.split("");
b = b.split("")
};
var len1 = a.length + 1,
len2 = b.length + 1,
I = 0,
i = 0,
d = [[0]],
c, j, J;
while (++i < len2)
d[0][i] = i;
i = 0;
while (++i < len1) {
J = j = 0;
c = a[I];
d[i] = [i];
while(++j < len2) {
d[i][j] = min(d[I][j] + 1, d[i][J] + 1, d[I][J] + (c != b[J]));
++J;
};
++I;
};
return d[len1 - 1][len2 - 1];
}
}(Math.min, false);
How can I work with algorithm (or a similar one) into my current code to sort it without bad performance?
UPDATE:
So I'm now using James Westgate's Lev Dist function. Works WAYYYY fast. So performance is solved, the issue now is using it with source...
modArr = limitArr.sort(function(a, b){
levDist(a, searchy)
levDist(b, searchy)
});
My problem now is general understanding on using the .sort() method. Help is appreciated, thanks.
Thanks!
I wrote an inline spell checker a few years ago and implemented a Levenshtein algorithm - since it was inline and for IE8 I did quite a lot of performance optimisation.
var levDist = function(s, t) {
var d = []; //2d matrix
// Step 1
var n = s.length;
var m = t.length;
if (n == 0) return m;
if (m == 0) return n;
//Create an array of arrays in javascript (a descending loop is quicker)
for (var i = n; i >= 0; i--) d[i] = [];
// Step 2
for (var i = n; i >= 0; i--) d[i][0] = i;
for (var j = m; j >= 0; j--) d[0][j] = j;
// Step 3
for (var i = 1; i <= n; i++) {
var s_i = s.charAt(i - 1);
// Step 4
for (var j = 1; j <= m; j++) {
//Check the jagged ld total so far
if (i == j && d[i][j] > 4) return n;
var t_j = t.charAt(j - 1);
var cost = (s_i == t_j) ? 0 : 1; // Step 5
//Calculate the minimum
var mi = d[i - 1][j] + 1;
var b = d[i][j - 1] + 1;
var c = d[i - 1][j - 1] + cost;
if (b < mi) mi = b;
if (c < mi) mi = c;
d[i][j] = mi; // Step 6
//Damerau transposition
if (i > 1 && j > 1 && s_i == t.charAt(j - 2) && s.charAt(i - 2) == t_j) {
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost);
}
}
}
// Step 7
return d[n][m];
}
I came to this solution:
var levenshtein = (function() {
var row2 = [];
return function(s1, s2) {
if (s1 === s2) {
return 0;
} else {
var s1_len = s1.length, s2_len = s2.length;
if (s1_len && s2_len) {
var i1 = 0, i2 = 0, a, b, c, c2, row = row2;
while (i1 < s1_len)
row[i1] = ++i1;
while (i2 < s2_len) {
c2 = s2.charCodeAt(i2);
a = i2;
++i2;
b = i2;
for (i1 = 0; i1 < s1_len; ++i1) {
c = a + (s1.charCodeAt(i1) === c2 ? 0 : 1);
a = row[i1];
b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
row[i1] = b;
}
}
return b;
} else {
return s1_len + s2_len;
}
}
};
})();
See also http://jsperf.com/levenshtein-distance/12
Most speed was gained by eliminating some array usages.
Updated: http://jsperf.com/levenshtein-distance/5
The new Revision annihilates all other benchmarks. I was specifically chasing Chromium/Firefox performance as I don't have an IE8/9/10 test environment, but the optimisations made should apply in general to most browsers.
Levenshtein Distance
The matrix to perform Levenshtein Distance can be reused again and again. This was an obvious target for optimisation (but be careful, this now imposes a limit on string length (unless you were to resize the matrix dynamically)).
The only option for optimisation not pursued in jsPerf Revision 5 is memoisation. Depending on your use of Levenshtein Distance, this could help drastically but was omitted due to its implementation specific nature.
// Cache the matrix. Note this implementation is limited to
// strings of 64 char or less. This could be altered to update
// dynamically, or a larger value could be used.
var matrix = [];
for (var i = 0; i < 64; i++) {
matrix[i] = [i];
matrix[i].length = 64;
}
for (var i = 0; i < 64; i++) {
matrix[0][i] = i;
}
// Functional implementation of Levenshtein Distance.
String.levenshteinDistance = function(__this, that, limit) {
var thisLength = __this.length, thatLength = that.length;
if (Math.abs(thisLength - thatLength) > (limit || 32)) return limit || 32;
if (thisLength === 0) return thatLength;
if (thatLength === 0) return thisLength;
// Calculate matrix.
var this_i, that_j, cost, min, t;
for (i = 1; i <= thisLength; ++i) {
this_i = __this[i-1];
for (j = 1; j <= thatLength; ++j) {
// Check the jagged ld total so far
if (i === j && matrix[i][j] > 4) return thisLength;
that_j = that[j-1];
cost = (this_i === that_j) ? 0 : 1; // Chars already match, no ++op to count.
// Calculate the minimum (much faster than Math.min(...)).
min = matrix[i - 1][j ] + 1; // Deletion.
if ((t = matrix[i ][j - 1] + 1 ) < min) min = t; // Insertion.
if ((t = matrix[i - 1][j - 1] + cost) < min) min = t; // Substitution.
matrix[i][j] = min; // Update matrix.
}
}
return matrix[thisLength][thatLength];
};
Damerau-Levenshtein Distance
jsperf.com/damerau-levenshtein-distance
Damerau-Levenshtein Distance is a small modification to Levenshtein Distance to include transpositions. There is very little to optimise.
// Damerau transposition.
if (i > 1 && j > 1 && this_i === that[j-2] && this[i-2] === that_j
&& (t = matrix[i-2][j-2]+cost) < matrix[i][j]) matrix[i][j] = t;
Sorting Algorithm
The second part of this answer is to choose an appropriate sort function. I will upload optimised sort functions to http://jsperf.com/sort soon.
I implemented a very performant implementation of levenshtein distance calculation if you still need this.
function levenshtein(s, t) {
if (s === t) {
return 0;
}
var n = s.length, m = t.length;
if (n === 0 || m === 0) {
return n + m;
}
var x = 0, y, a, b, c, d, g, h, k;
var p = new Array(n);
for (y = 0; y < n;) {
p[y] = ++y;
}
for (; (x + 3) < m; x += 4) {
var e1 = t.charCodeAt(x);
var e2 = t.charCodeAt(x + 1);
var e3 = t.charCodeAt(x + 2);
var e4 = t.charCodeAt(x + 3);
c = x;
b = x + 1;
d = x + 2;
g = x + 3;
h = x + 4;
for (y = 0; y < n; y++) {
k = s.charCodeAt(y);
a = p[y];
if (a < c || b < c) {
c = (a > b ? b + 1 : a + 1);
}
else {
if (e1 !== k) {
c++;
}
}
if (c < b || d < b) {
b = (c > d ? d + 1 : c + 1);
}
else {
if (e2 !== k) {
b++;
}
}
if (b < d || g < d) {
d = (b > g ? g + 1 : b + 1);
}
else {
if (e3 !== k) {
d++;
}
}
if (d < g || h < g) {
g = (d > h ? h + 1 : d + 1);
}
else {
if (e4 !== k) {
g++;
}
}
p[y] = h = g;
g = d;
d = b;
b = c;
c = a;
}
}
for (; x < m;) {
var e = t.charCodeAt(x);
c = x;
d = ++x;
for (y = 0; y < n; y++) {
a = p[y];
if (a < c || d < c) {
d = (a > d ? d + 1 : a + 1);
}
else {
if (e !== s.charCodeAt(y)) {
d = c + 1;
}
else {
d = c;
}
}
p[y] = d;
c = a;
}
h = d;
}
return h;
}
It was my answer to a similar SO question
Fastest general purpose Levenshtein Javascript implementation
Update
A improved version of the above is now on github/npm see
https://github.com/gustf/js-levenshtein
The obvious way of doing this is to map each string to a (distance, string) pair, then sort this list, then drop the distances again. This way you ensure the levenstein distance only has to be computed once. Maybe merge duplicates first, too.
I would definitely suggest using a better Levenshtein method like the one in #James Westgate's answer.
That said, DOM manipulations are often a great expense. You can certainly improve your jQuery usage.
Your loops are rather small in the example above, but concatenating the generated html for each oneResult into a single string and doing one append at the end of the loop will be much more efficient.
Your selectors are slow. $('.oneResult') will search all elements in the DOM and test their className in older IE browsers. You may want to consider something like atRes.find('.oneResult') to scope the search.
In the case of adding the click handlers, we may want to do one better avoid setting handlers on every keyup. You could leverage event delegation by setting a single handler on atRest for all results in the same block you are setting the keyup handler:
atRest.on('click', '.oneResult', function(){
window.location.href = 'http://hashtag.ly/' + $(this).html();
});
See http://api.jquery.com/on/ for more info.
I just wrote an new revision: http://jsperf.com/levenshtein-algorithms/16
function levenshtein(a, b) {
if (a === b) return 0;
var aLen = a.length;
var bLen = b.length;
if (0 === aLen) return bLen;
if (0 === bLen) return aLen;
var len = aLen + 1;
var v0 = new Array(len);
var v1 = new Array(len);
var i = 0;
var j = 0;
var c2, min, tmp;
while (i < len) v0[i] = i++;
while (j < bLen) {
c2 = b.charAt(j++);
v1[0] = j;
i = 0;
while (i < aLen) {
min = v0[i] - (a.charAt(i) === c2 ? 1 : 0);
if (v1[i] < min) min = v1[i];
if (v0[++i] < min) min = v0[i];
v1[i] = min + 1;
}
tmp = v0;
v0 = v1;
v1 = tmp;
}
return v0[aLen];
}
This revision is faster than the other ones. Works even on IE =)

Factorials/Combinations Yields NaN When Not Supposed To

I am solving for y Choose p combinations. I am a beginner with Javascript.
I have produced this definition of the factorial function:
It was inteded to do x * (x-1) * (x-2) ... * 1.
function factorial(z)
{
var product = z;
if (z == 0)
{
return 1;
}
else
{
for (var m = 1; m < z; m++)
{
product = m * product;
return product;
}
}
}
I then have this function, which uses the factorial function.
function placeBoxes()
{
var ids = 0;
for (var y = 0; y < (numOfRows-1); y++)
{
for (var p = 0; p < (y+1); p++, ids++)
{
x = document.createElement('div');
x.className = "box";
x.id = ids;
x.innerHTML = (factorial(y))/((factorial(y-p))*(factorial(p)));
document.getElementById('holdsBoxes').appendChild(x);
}
}
}
It is supposed to choose the combinations. For experimental purposes, numOfRows is realistically between 5 and 30. 0C0 1C0 1C1 2C0 2C1 2C2 and so on...
This is equivalent to 1, 1, 1, 1, 2, 1 and so on...
Does anyone know what I have done wrong? I am getting NaN instead of a value for the second, third, fifth, eighth, ninth, and many other values.
Edit: Thank you everyone! The problem is solved. The factorial function was messed up.
Change
for (var m = 1; m < z; m++)
{
product = m * product;
return product;
}
To
for (var m = 1; m < z; m++)
{
product = m * product;
}
return product;
You're never completing the loop
for (var m = 1; m < z; m++)
{
product = m * product;
return product;
}
Your returning product inside your loop. Are you sure about this? Don't you want to return product outside your loop?
This is also the cause of your NaN. What if z is 1 ? then m < z is m < 1 and thats always false. So that loop body is never being called. and the return statement is never called.
So the function returns undefined. And undefined * 1 === NaN
I believe that the factorial function is incorrect. Try changing it to this:
function factorial(z)
{
var product = z;
if (z == 0)
{
return 1;
}
else
{
for (var m = 1; m < z; m++)
{
product = product*(product - m);
}
return product;
}
}

Categories