I tried to rewrite this indexOf MDN example to practice recursion
var str = 'To be, or not to be, that is the question.';
var count = 0;
var pos = str.indexOf('e');
while (pos !== -1) {
count++;
pos = str.indexOf('e', pos + 1);
}
console.log(count); // displays 4
This was my solution:
var count = 0;
function countLetters(str, p) {
var pos = str.indexOf(p);
if (pos == -1) {
return count;
}
else {
count ++;
return countLetters(str.substr(pos + 1), p)
}
}
console.log(countLetters('To be, or not to be, that is the question.', 'e'));
It works, but is there anyway to get the count variable inside the function itself? Is it not really a true recursion if I have a count variable outside the function?
In a recursive function, if you want to keep a variable around from one "iteration" to the next, then you need to pass it as an argument:
function countLetters(str, p, count) {
count = count || 0;
var pos = str.indexOf(p);
if (pos == -1) {
return count;
}
else {
return countLetters(str.substr(pos + 1), p, count + 1);
}
}
console.log(countLetters('To be, or not to be, that is the question.', 'e'));
// => 4
However, this is not always necessary, as Arun P Johny's answer illustrates.
What you can do is to return the count value form the method, so if the item is not found you return 0, else you return 1 + value-of-recursive-call
function countLetters(str, p) {
var pos = str.indexOf(p);
if (pos == -1) {
return 0;
} else {
return 1 + countLetters(str.substr(pos + 1), p)
}
}
console.log(countLetters('To be, or not to be, that is the question.', 'e'));
Demo: Fiddle
Related
I am trying to get the sum of an array of prime numbers, and I understand there are more elegant ways to do that and have seen the links to those solutions.
My problem is something that's wrong within this specific script, and I'm trying to understand what's causing THIS code to fail.
The issue is that the numbers 9, 15 and many others are being being added into the primes array, even though they all, correctly, fail a test to check if they're prime numbers. I can't wrap my head around what in the script is causing the numbers to push to the array despite failing that test. Again, I'm not looking for a completely different/better approach to summing the primes, but some help in identifying what exactly is wrong in this script would be really appreciated.
function totalPrime(num) {
var nums = [];
var primes = [];
for (var i = 1;
(num - i) > 1; i++) {
nums.push(num - i);
}
nums.forEach(isPrime);
function isPrime(n) {
var a = [];
var test;
if (n === 1) {} else if (n === 2) {
primes.push(n);
} else {
for (var i = 1;
(n - i) > 1; i++) {
a.push(n - i);
}
a.forEach(function(x) {
if ((n % x) === 0) {
test = false;
} else {
test = true;
}
});
if (test) {
primes.push(n);
} else {}
};
}
console.log(primes.reduce(function(a, b) {
return a + b
}));
}
totalPrime(5);
Same script with logging I was using to debug:
function totalPrime(num) {
var nums = [];
var primes = [];
for (var i = 1;
(num - i) > 1; i++) {
nums.push(num - i);
}
nums.forEach(isPrime);
function isPrime(n) {
var a = [];
var test;
if (n === 1) {
console.log(n + ' is NOT a prime number');
} else if (n === 2) {
console.log(n + ' IS a prime number');
primes.push(n);
} else {
for (var i = 1;
(n - i) > 1; i++) {
a.push(n - i);
}
a.forEach(function(x) {
if ((n % x) === 0) {
test = false;
console.log(n + ' % ' + x + ' equals 0');
console.log(x + ' fails check');
} else {
test = true;
console.log(n + ' % ' + x + ' does NOT equal 0');
console.log(x + ' passes check');
}
});
if (test) {
console.log(n + ' IS a prime number.');
primes.push(n);
} else {
console.log(n + ' is NOT a prime number.');
}
};
}
console.log(primes);
console.log(primes.reduce(function(a, b) {
return a + b
}));
}
totalPrime(5);
Your test value in each test override the previous check. Thus, actualy only the last check (divide in 2) become relevant, and all the odd primes fail.
You can correct it by change the default of test to true, and remove the exist line in the code test = true;.
The corrected code:
function isPrime(n) {
var a = [];
var test = true;
if (n === 1) {} else if (n === 2) {
primes.push(n);
} else {
for (var i = 1;
(n - i) > 1; i++) {
a.push(n - i);
}
a.forEach(function(x) {
if ((n % x) === 0) {
test = false;
}
});
if (test) {
primes.push(n);
}
};
}
Is there a javascript/jquery method or function that will let me split a string at nth occurrence of a selected delimiter? I'd like it work just like the regular str.split(delimiter) except instead of splitting at every occurrence of the delimiter it could be instructed to skip n number of them each time.
var str = "A,BB,C,DDD,EEEE,F";
var strAry = str.split(",");
Would result in strAry looking like {"A","BB","C","DDD","EEEE","F"}
What I want would be {"A,BB","C,DDD","EEEE,F"} assuming I set nth occurance to 2.
I wrote a small function that appears to work but hoping there was a simpler way to do this:
function splitn(fullString, delimiter, n){
var fullArray = fullString.split(delimiter);
var newArray = [];
var elementStr = "";
for(var i = 0; i < fullArray.length; i++) {
if (i == fullArray.length-1) {
if (elementStr.length == 0) {
elementStr = fullArray[i];
} else {
elementStr += (delimiter + fullArray[i]);
}
newArray.push(elementStr);
} else {
if (((i + 1) % n) == 0) {
if (elementStr.length == 0) {
elementStr = fullArray[i];
} else {
elementStr += (delimiter + fullArray[i]);
}
newArray.push(elementStr);
elementStr = "";
} else {
if (elementStr.length == 0) {
elementStr = fullArray[i];
} else {
elementStr += (delimiter + fullArray[i]);
}
}
}
};
return newArray;
};
Thanks.
You could simply use Array.prototype.reduce() to modify the array returned by split to your liking. The idea is similar to your code, just shorter.
function modify(str, n, delim) {
return str.split(delim).reduce(function(output, item, i) {
if (!(i % n)) {
output.push(item);
} else {
output[i / n | 0] += delim + item;
};
return output;
}, []);
};
modify("A,BB,C,DDD,EEEE,F", 3, ','); //["A,BB,C", "DDD,EEEE,F"]
modify("A,BB,C,DDD,EEEE,F", 2, ','); //["A,BB", "C,DDD", "EEEE,F"]
EDIT: Just noticed you wanted to use an arbitrary "nth" value. I updated it so you can simply change the nth to whatever positive integer you like.
Here's a way that takes advantage of the second argument to .indexOf() so that you can anchor your searches from after the last ending point in the string:
function splitn(fullString, delimiter, n) {
var lastIdx = 0
, idx = -1
, nth = 0
, result = [];
while ((idx = fullString.indexOf(delimiter, idx + delimiter.length)) !== -1) {
if ((nth = ++nth % n) === 0) {
result.push(fullString.slice(lastIdx, idx));
lastIdx = idx + 1;
}
}
result.push(fullString.slice(lastIdx));
return result;
}
var result = splitn("A,BB,C,DDD,EEEE,F", ",", 2);
document.body.innerHTML = "<pre>" + JSON.stringify(result, null, 4) + "</pre>";
I have an array with 3 types of values in which I wish to sort them.
If I only use one variable it goes all pretty well, but it all goes wrong when i want to use 3 types of variables to determine sorting order.
First variable condition: if obj.sortorder == 999999 send it to the end of the line(there is only one of this one);
if not true then
if (date < other date) put it in front of the one before
if(date > other date) put it behind the other one
if dates are equal look to sortorder to determine the order in which to apppear.
Then loop over array, reset all sortorder variables to be properly ascending in the new order.
Then splice in a new value(15th), but then it doesn't appear next to the other one, even though they have duplicate values.
My head hurts from trying to figure this one out, I just can't seem to get them in the right order.
Basically the way they are created here they should come out in the first sort. But yet the first sort is messed up with values all over the place except where I want them.
The second sort puts them miraculously in the right order but puts the 16 between the two fifteens whilst the fifteens should be next to eachother. and somehow the 24th ends up as the 9999 after the reassignment whilst the 29th should have remained as the last one.
Who can help me with this?
If you press run code snippet you get the garbled output I currently get.
The first set is what all the others should look like, except for the last one where the 15's should be hugging eachother.f
elements = [];
for (var c = 0; c < 30; c++) {
elements[c] = {
sortorder: c,
getDate: function () {
return new Date(2015, 06, this.sortorder)
}
};
}
function log(what) {
var elem = document.getElementById('sortorder');
elem.appendChild(document.createTextNode(what + "\n"));
}
for (c = 1; c < elements.length; c++) {
log(c + " = " + elements[c].getDate() + " - " + elements[c].sortorder)
}
log('--------------------------------');
elements[elements.length - 1].sortorder = 9999999;
this.elements.sort(function (one, two) {
/**
* Failsafe to prevent the last element to be placed in the middle
*/
if (one.sortorder >= 9999998) {
return 1;
}
if (two.sortorder >= 9999998) {
return -1;
}
if (one.getDate() < two.getDate()) {
return -1
}
if (two.getDate() > one.getDate()) {
return 1;
}
if (one.sortorder < two.sortorder) {
return -1;
}
if (one.sortOrder > two.sortorder) {
return 1;
}
return 0;
});
function log(what) {
var elem = document.getElementById('sortorder');
elem.appendChild(document.createTextNode(what + "\n"));
}
for (c = 1; c < elements.length; c++) {
log(c + " = " + elements[c].getDate() + " - " + elements[c].sortorder)
}
log('--------------------------------------------------------------');
elements.splice(17, 0, {
sortorder: 15,
getDate: function () {
return new Date(2015, 06, 15)
}
});
for (var c = 1; c < this.elements.length; c++) {
if (c < this.elements.length - 1) {
this.elements[c].sortorder = c;
} else {
this.elements[c].sortorder = 9999999;
}
}
for (c = 1; c < elements.length; c++) {
log(c + " = " + elements[c].getDate() + " - " + elements[c].sortorder)
}
<pre id="sortorder">
</pre>
After some experimenting, fiddling, swearing, googling, the normal process in a situation like this I finally got the solution.
I guess I was overthinking things once again.
Thanks for helping out and thinking along.
elements.sort(function(one,two)
{
var ret = 0;
/**
* Failsafe to prevent the last element to be placed in the middle
*/
if(one.sortorder >= 9999998) {
ret = 1;
}
else {
if(two.sortorder >= 9999998) {
ret = -1;
}
else {
if(one.getDate() - two.getDate() !== 0) {
ret = one.getDate() - two.getDate();
}
else {
ret = one.sortorder - two.sortorder;
}
}
}
console.log(ret);
return ret;
});
Not quite sure what you mean by "Then splice in a new value(15th), but then it doesn't appear next to the other one, even though they have duplicate values."
This does everything but that.
var last;
var newArray = [];
for(var obj in array){
obj = array[obj];
if(obj.sortorder === 999999)
last = obj;
else {
for(var item in newArray){
if(obj.date.getTime() < newArray[item].date.getTime()){
newArray.splice(item, 0, obj);
break;
}
if(obj.date.getTime() === newArray[item].date.getTime()){
if(obj.sortorder > newArray[item].sortorder){
newArray.splice(item, 0, obj);
break;
}
else{
newArray.splice(item + 1, 0, obj);
break;
}
}
}
}
}
newArray.push(last);
var sortorder = 1;
for(var item in newArray){
if(newArray[item].date.getTime() > newArray[item - 1].date.getTime())
newArray[item].sortorder = ++sortorder;
}
I'm attempting to get better with optimizing algorithms and understanding big-o, etc.
I threw together the below function to calculate the n-th Fibonacci number. This works (for a reasonably high input). My question is, how can I improve this function? What are the drawbacks of calculating the Fibonacci sequence this way?
function fibo(n) {
var i;
var resultsArray = [];
for (i = 0; i <= n; i++) {
if (i === 0) {
resultsArray.push(0);
} else if (i === 1) {
resultsArray.push(1);
} else {
resultsArray.push(resultsArray[i - 2] + resultsArray[i - 1]);
}
}
return resultsArray[n];
}
I believe my big-o for time is O(n), but my big-o for space is O(n^2) due to the array I created. Is this correct?
If you don't have an Array then you save on memory and .push calls
function fib(n) {
var a = 0, b = 1, c;
if (n < 3) {
if (n < 0) return fib(-n);
if (n === 0) return 0;
return 1;
}
while (--n)
c = a + b, a = b, b = c;
return c;
}
Performance Fibonacci:
var memo = {};
var countInteration = 0;
var fib = function (n) {
if (memo.hasOwnProperty(n)) {
return memo[n];
}
countInteration++;
console.log("Interation = " + n);
if (n == 1 || n == 2) {
result = 1;
} else {
result = fib(n - 1) + fib(n - 2);
}
memo[n] = result;
return result;
}
//output `countInteration` = parameter `n`
I am learning js now..
I am trying to write a simple js programme..
what I am trying to do is to print all valid combinations of n-pair
of parenthesis(properly opened and closed)
eg (), (()()),(())
i have written the logic can you tell me whether its correct or not
https://jsfiddle.net/e7mcp6xb/
module.exports = Parentheses = (function() {
var _isParenthesesMatch = function(str) {
var parentheses = str.length;
var rightParentheses = '(';
var leftParentheses = ')';
var rightCount = 0;
var leftCount = 0;
for(i=0;i<=str.length;i++){
if(rightParentheses == str.charAt(i))
{
rightCount++;
}
else if(leftParentheses == str.charAt(i))
{
leftCount++;
}
}
if(rightCount == leftCount){
return true;
}
else(rightCount != leftCount){
return false;
}
}
}());
The check is wrong, but You can fix it easily: In each step of the for loop the number of opening parenthesis cannot be smaller than the number of closing ones:
if (rightCount < leftCount)
return false;
The whole function should look like this:
function(str) {
var rightParentheses = '(';
var leftParentheses = ')';
var rightCount = 0;
var leftCount = 0;
for (var i = 0; i <= str.length; i++) {
if (rightParentheses == str.charAt(i))
rightCount++;
else if (leftParentheses == str.charAt(i))
leftCount++;
if (rightCount < leftCount)
return false;
}
return rightCount == leftCount;
}
If You'd like to generate all valid strings, you can use this function:
function nPair(n) {
if (n == 0)
return [""];
var result = [];
for (var i = 0; i < n; ++i) {
var lefts = nPair(i);
var rights = nPair(n - i - 1);
for (var l = 0; l < lefts.length; ++l)
for (var r = 0; r < rights.length; ++r)
result.push("(" + lefts[l] + ")" + rights[r]);
}
return result;
}
// result of nPair(3):
// ["()()()", "()(())", "(())()", "(()())", "((()))"]
Try this, i have modified your code a little bit. Modification and its explanation is marked in comments.
module.exports = Parentheses = (function() {
var _isParenthesesMatch = function(str) {
var parentheses = str.length;
var rightParentheses = '(';
var leftParentheses = ')';
var count=0;
for(i=0;i<str.length;i++){
//this is to check valid combination start always from ( and end with )
if(str.charAt(0)==rightParentheses && str.length-1==leftParentheses)
{
if(rightParentheses == str.charAt(i))
{
count++; //this will calculate how many times rightParentheses is present & increment count by 1
}
else if(leftParentheses == str.charAt(i))
{
count--; //this will simply decrement count to match valid sequence
}
}
if(count==0){
return true;
}
}
}());
Your function is wrong, try checking if left and right parenthesis and balanced:
function isValid(str){
var stripedStr = str.replace(/[^\(\)]+/g, '');
return stripedStr.split('').reduce(function(a, b){
return a > -1 ? b === '(' ? a + 1 : a - 1 : -1;
}, 0) === 0;
}
stripedStr - use replace() to remove any characters that are not ( or ).
split('') - returns an array so we can use reduce.
reduce() - applies a function against an accumulator and each value of the array (from left-to-right) has to reduce it to a single value.
The reduce starts with 0 as initial value and in the reduce function we count parenthesis
(+1 for (, -1 for ) )
Our string is valid if our counter never goes below 0 and we end up with 0.
You can write the reduce function like this too:
function(previousValue, currentValue){
if (previousValue > -1){
if (currentValue === '('){
return previousValue + 1;
} else {
return previousValue - 1;
}
}
return -1;
}
This is equivalent to:
function(a, b){
return a > -1 ? b === '(' ? a + 1 : a - 1 : -1;
}
It is wrong, because your function will return true for this example ))(( or this ())(()