I'm trying to write a recursive program to count the number of times a substring ("cat") appears in a string ("catdogcowcat"). Not sure what I'm doing wrong, but I keep getting the following error:
TypeError: Cannot read property 'length' of undefined
Here's my code:
function strCount (str, sub) {
var subLen = sub.length;
var strLen = str.length;
if (strLen < subLen) {
return 0;
} else if (str.slice(0, subLen) === sub) {
return 1 + strCount(str.substring(subLen));
} else return strCount(str.substring(1));
}
I think it's breaking when I try to get the length of the substring on this line, but that's just my guess based on my infantile understanding of devtools debugging:
return 1 + strCount(str.substring(subLen));
Thanks!
Your strCount function takes 2 arguments, so make sure you pass sub when you call it recursively:
function strCount (str, sub) {
var subLen = sub.length;
var strLen = str.length;
if (strLen < subLen) {
return 0;
} else if (str.slice(0, subLen) === sub) {
return 1 + strCount(str.substring(subLen), sub);
} else return strCount(str.substring(1), sub);
}
You could use regular expression, with match instead of having to do a recursive function
function strCount(needle,haystack){
var r = new RegExp(needle,"g");
var r2 = haystack.match(r);
return (r2?r2.length:0);
}
console.log( strCount("cat","catdowcowcat") );
you need to pass value for sub ..
function strCount(str, sub) {
var subLen = sub.length;
var strLen = str.length;
if (strLen < subLen) {
return 0;
} else if (str.slice(0, subLen) === sub) {
return 1 + strCount(str.substring(subLen),sub);
} else
return strCount(str.substring(1),sub);
}
you can call the method
$(document).ready(function(){
alert(strCount("catdogcowcat","cat"));
});
It will return the result as 2.
Fiddle
http://jsfiddle.net/deepaksuresh3003/RDmby/
you are calling your own method strCount(str.substring(subLen)) without providing second parameter and hence the function is taking 'sub' parameter as undefined.
Update your code as follows and it will start working:
function strCount(str, sub) {
var subLen = sub.length;
var strLen = str.length;
if (strLen < subLen) {
return 0;
} else if (str.slice(0, subLen) === sub) {
return 1 + strCount(str.substring(subLen), sub);
} else return strCount(str.substring(1),sub);
}
Related
Yes I know we can use indexOf and includes or a regular expression to find weather a string is present in another string.
But we have a different requirement. We would like indexOf or includes function to return true even if partial string is matched not the whole world. Let me provide an example.
Let's say my username is "Animation". The string the I am entering is "sssrtAnimyt5678". Now as the string "sssrtAnimyt5678" contains "Anim" which is present in "Animation" we want the function to return true.
The problem with indexOf, includes and regular expression is it tries to find the whole word "Animation" but not the partial word "Anim". I even used KMP Algorithm and found out that even KMP searches for "Animation" not "Anim". Below is the implementation of KMP in Javascript.
var makeKMPTable = function(word) {
if(Object.prototype.toString.call(word) == '[object String]' ) {
word = word.split('');
}
var results = [];
var pos = 2;
var cnd = 0;
results[0] = -1;
results[1] = 0;
while (pos < word.length) {
if (word[pos - 1] == word[cnd]) {
cnd++;
results[pos] = cnd;
pos++;
} else if (cnd > 0) {
cnd = results[cnd];
} else {
results[pos] = 0;
pos++;
}
}
return results;
};
var KMPSearch = function(string, word) {
if(Object.prototype.toString.call(string) == '[object String]' ) {
string = string.split('');
}
if(Object.prototype.toString.call(word) == '[object String]' ) {
word = word.split('');
}
var index = -1;
var m = 0;
var i = 0;
var T = makeKMPTable(word);
while (m + i < string.length) {
if (word[i] == string[m + i]) {
if (i == word.length - 1) {
return m;
}
i++;
} else {
m = m + i - T[i];
if (T[i] > -1) {
i = T[i];
} else {
i = 0;
}
}
}
return index;
};
console.log(KMPSearch("sssrtAnimyt5678", "Animation")); // returns -1
So I would like to know if such kind of partial search is possible and if anybody can point me to such implementation details or algorithm it would be helpful.
Thanks in Advance.
Just check any possible substring.
const
hasCommon = (a, b) => {
for (let i = 0; i < a.length; i++) {
for (let j = i + 1; j <= a.length; j++) {
if (b.includes(a.slice(i, j))) return true;
}
}
return false;
};
console.log(hasCommon('Animation', 'sssrtAnimyt5678'));
I have
function remove(s) {
for (i = 0; i < s.length; i++) {
let lastChar = s.slice(-1);
if (lastChar === "!") {
s = s.substring(0, s.length - 1);
}
else {
return s;
}
}
return s;
}
And this is passing 105 tests but failing 1 on codewars.
The test that it's failing is:
Expected: '\'isl\'', instead got: '\'isl!\'' for when (s) is "isl!!!!!"
I can't figure out why, in this case, it's not removing the last character in the string.
This should be removing the last character in the string whenever it's !:
if (lastChar === "!") {
s = s.substring(0, s.length - 1);
}
I've also tried:
s = s.replace("!", "");
But same result. Any ideas?
Because you're increasing i and checking i < s.length on each loop. At one point, you remove a ! (thus shortening the string) and i is equal to s.length and you never check the last char.
There's no reason for i at all. (Or a for loop, but if that was the requirement in the challenge...)
If you step through it with your debugger, you'll see the problem. This version using console.log also shows the problem:
function remove(s) {
for (i = 0; i < s.length; i++) {
let lastChar = s.slice(-1);
if (lastChar === "!") {
s = s.substring(0, s.length - 1);
console.log(`i = ${i}, s = '${s}', s.substring(i) = '${s.substring(i)}'`);
}
else {
console.log(`returning '${s}'`);
return s;
}
}
console.log(`returning '${s}' at end, because ${i} >= ${s.length}`);
return s;
}
remove("isl!!!!!");
.as-console-wrapper {
max-height: 100% !important;
}
You can do this without using for loop.
const stringRemover (str) => {
if (str[str.length-1] === "!") {
return str.slice(0,str.length-1);
} else {
return str;
}
}
You can create a recursive function and check if the last char using CharAt if it is !. If it is so then again call the same function but with new string which is created after removing the last !
Not sure why the for is needed if the last character is needed
function remove(str) {
let getLastChar = str.charAt(str.length - 1);
if (getLastChar === '!') {
return remove(str.substring(0, str.length - 1))
} else {
return str;
}
}
console.log(remove("isl!!!!!"));
Here is codewars result
Here is result
As answered in a previous reply, i < s.length is checked in every iteration in a for loop.
Try this :
function remove(s) {
let a = s.length;
for (i = 0; i < a; i++) {
let lastChar = s.slice(-1);
if (lastChar === "!") {
s = s.substring(0, s.length - 1);
}
else {
return s;
}
}
return s;
}
#T.J. Crowder pointed me in the right direction, but he didn't provide an answer that followed my original logic (in this case I wanted to use a for-loop).
The key takeaway is that s = s.replace("!", ""); will work when i-- and s = s.replace(/!+$/g, '') will work when i++. Because, as far as I understand, the replace() method only replaces the first occurrence of the string, which is why we need i-- to force the loop to iterate backwards through the string, making sure that every occurance of "!" gets replaced.
I.e. this will work:
function remove(s) {
for (i = 0; i < s.length; i--) {
let lastChar = s.slice(-1);
if (lastChar === "!") {
s = s.replace("!", '')
}
else {
return s;
}
}
return s;
}
And this will also work:
function remove(s) {
for (i = 0; i < s.length; i++) {
let lastChar = s.slice(-1);
if (lastChar === "!") {
s = s.replace(/!+$/g, '');
}
else {
return s;
}
}
return s;
}
In my palindrome function an if-else-statement returns undefined. Basically, I am trying to find the biggest palindromic number with three digits. For example with two digits: 99 * 91 = 9009.
var palindromic = function(n) {
var save,
result,
counter = 900;
var checker = function(string) {
s = string.toString();
if(!(s)) {
return true;
} else if(s[0] !== s[s.length - 1]) {
return false;
}
checker(s.slice(1, -1));
}
var recursive = function() {
result = counter * n;
if(counter === n) {
return;
} else if(checker(result)) { // this line of code here, undefined.
save = result;
}
counter++;
recursive();
}
recursive();
return save;
};
What is wrong? Any help is welcome!
There are two problems in the code
checker() should have return checker(s.slice(1,-1)); as last line.
In recursive() when checker(result) is true recursive() should return.
Here's corrected code.
var palindromic = function (n) {
var save,
result,
counter = 900;
var checker = function (s) {
//s = string.toString();
if ( !(s) ) {
return true;
} else if ( s[0] !== s[s.length-1] ) {
return false;
}
return checker(s.slice(1,-1));
}
var recursive = function () {
result = counter * n;
if ( counter === n ) {
return;
} else if ( checker(result + "") ) { // this line of code here, undefined.
save = result;
return;
}
counter++;
recursive();
}
recursive();
return save;
};
Output:
palindromic(2)
2002
palindromic(3)
2772
palindromic(5)
5005
palindromic(6)
6006
palindromic(9)
8118
palindromic(23423)
188484881
A little spoiler and improving
You can do it without a recursion.
Usage of a reverse function to reverse a string.
Usage of two for loops, starting from the highest number.
function strReverse(str) {
var reverse = "";
for(var i = (str.length - 1); i >= 0; i -= 1) {
reverse += str[i];
}
return reverse;
}
function palindromic(n) {
var highestPalindrom = 0;
// Start with the highest number!
for(var i = n; i > 1; i -= 1) {
// Start also with the highest number!
for(var j = n; j > 1; j -= 1) {
// Get product
var product = i * j;
// Compare the string in reverse with the string itself
// If it is true, then it is a palindrom!
if(strReverse(product.toString()) === product.toString()) {
highestPalindrom = product;
// Break inner loop
break;
}
}
// Break outer loop
break;
}
return highestPalindrom;
}
var hP = palindromic(99);
console.log(hP);
I'm not sure what I'm doing wrong here. The first instance that I use indexOf it works perfectly fine, but when I use it the second time it's not returning the result that I'm expecting.
function mutation(arr) {
//return arr;
res = "";
for (var x=0; x<arr[1].split("").length; x++) {
if (arr[0].indexOf(arr[1].split("")[x]) !== -1) {
res += "t";
} else {
res += "f";
}
}
// res = ttt
if (res.indexOf("f") !== -1) {
return true;
} else {
return false;
}
}
mutation(["hello", "hey"]);
// this returns true instead of false
mutation(["floor", "loo"]);
// returns false instead of true
mutation should return false if an element from arr[1] is not present in arr[0] else return true.
your code isn't working because when you say:
res.indexOf("f") != -1
this means: "I found an f", but you're treating it as if it means "I did not find an f".
In your case that you want to return false if you find an 'f', but you're returning true. Flip your true and false cases:
if (res.indexOf("f") != -1) {
return false;
} else {
return true;
}
ALSO your for loop is wrong because x starts at 0, so you need to go to < length not <= length of your string.
for (var x=0; x < arr[1].split("").length; x++) {
and now your code works as you wanted it to.
Just edited your code. Click on the <p> to check:
function mutation(arr) {
//return arr;
res = "";
for (var x=0; x< arr[1].split("").length; x++) {
res += arr[0].indexOf(arr[1].split("")[x]) > -1 ? 't' : 'f';
}
return res.indexOf('f') > -1;
}
$('p').click(function(){
alert(mutation(["hello", "hey"]));
alert(mutation(["floor", "loo"]));
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Click me</p>
If you simplify the logic a bit, that's easier to check:
function mutation(arr) {
return arr[1].split('').reduce(function(res, x) {
return arr[0].indexOf(x) >= 0;
}, true);
}
Thanks Leon for the correction.
I tried to not chance your logic, the mistake are:
You're trying to compare with all characters on the array[0], not only the first.
If you find a character equals on the first character on array[0] you should return true.
Correct code:
function mutation(arr) {
res = "";
for (var x=0; x<=arr[1].split("").length; x++) {
if (arr[0].split("")[0].indexOf(arr[1].split("")[x]) !== -1) {
return true;
}
}
return false;
}
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 ())(()