You are given a string with words and numbers separated by whitespaces (one space). The words contains only letters. You should check if the string contains three words in succession. For example, the string "start 5 one two three 7 end" contains three words in succession.
Input : String
Output : Boolean
This is what I'm trying to do, please point out my mistake. Thanks.
function threeWords(text){
let lst = text.split(' ');
for (let i=0; i< 3; i++) {
if (typeof lst[i] === 'string' && Number(lst[i]) === NaN) {return true}
else {return false;}}
}
If you'd rather continue with your code than use regex, here are your issues:
You only loop over 3 of the elements in lst. Loop over the entire length of the list.
You try to check if Number('somestring') === NaN. In JavaScript, NaN === NaN is False. Use isNaN() instead.
Once you find a list element that is not a number, you return True. You should have a variable that keeps track of how many words there are in succession (resetting to 0 when you find a number), and return True when this variable is equal to 3.
Here is the fixed code:
function threeWords(text) {
let lst = text.split(' ');
let num_words = 0;
for (let i = 0; i < lst.length; i++) {
if (isNaN(Number(lst[i])))
num_words++
else
num_words = 0
if (num_words === 3)
return true
}
return false;
}
Might be easier with a regular expression:
const result = /([A-Za-z]+( |$)){3}/.test('start 5 one two three 7 end');
console.log(result);
This is from LeetCode - Valid Palindrome.
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
Note: For the purpose of this problem, we define empty string as valid palindrome.
while (regex.test(s[start])) {
start++;}
--> can't understand how it works, I understood only that s[start] is alphanumeric characters, it will be false
if (!s[start] || !s[end])
--> What does this mean?
Below is the whole code
var isPalindrome = function(s) {
let regex = /[\W]/;
let start = 0;
let end = s.length - 1;
while (start < end) {
// Moves front runner to next alphanumeric
while (regex.test(s[start])) {
start++;
}
// Moves back runner to next alphanumeric
while (regex.test(s[end])) {
end--;
}
// Above would run until null if there are no alphanumeric characters so return true
if (!s[start] || !s[end]) {
return true;
}
// Check if equal and return false if not
if (s[start].toLowerCase() != s[end].toLowerCase()) {
return false;
}
// If index values match continue the while loop
start++;
end--;
}
return true;
};
Please Advise!
Same as previous solution, plus:
+ removing spaces and symbols, except (A-Z,a-z,0-9)
+ lowercasing
const isPalindrome = function(str) {
const expr = /[\W_]/g;
const lowcaseStr = str.toLowerCase().replace(expr, '');
const reverseStr = lowcaseStr.split('').reverse().join('');
return lowcaseStr === reverseStr
};
This is heavily over-engineered. Why not just use one for loop with 2 counters, one starting at 0 and one at the last index and, while they aren't equal, check if the characters at those indices are the same. Or use built in functions like
function palindrome(str){ return str.split('').reverse().join('') == str}
I am trying to learn how this problem has been solved but I am lost at string.slice(0,1) and i++ after that.
What is the need to use the slice method?
The questions is:
Write a function called countChars that accepts two parameters: a string and a character. This function should return a number representing the number of times that the character appears in string.
function countChars(string, character) {
let count = 0;
let i = 0;
while (i < string.length) {
if (string[i] === character) {
count++;
}
string.slice(0, 1);
i++;
}
return count;
}
Nina already solved it using your code, a shorter option would be using String.match
function countChars(string, character) {
const { length } = string.match(new RegExp(character, 'ig')) || [];
return length;
}
console.log(countChars('Foobar', 'o'));
Explanation of your code:
function countChars(string, character) {
let count = 0; // set variable count to zero
let i = 0; // set variable i to zero
while (i < string.length) { // loop while i is less than lenght of string
if (string[i] === character) { // check character at position i
count++; // Increment count by one
}
string.slice(0, 1); // returns the first character in string, but return value is not used. Can be removed
i++; // increment variable i by one
}
return count; // returns count
}
console.log("Count", countChars("ABCDABC", "A"));
string.slice(0, 1) The slice method extracts a section of a string and returns it as a new string, without modifying the original string. The return value is not used in this function, so you can remove the call. I guess that the person who wrote it tried to remove the first character of the string for each iteration of the loop. That is not a good way to solve the problem, for example because it creates one string per iteration and wastes memory.
i++ The increment operator ++ increments (adds one to) its operand and returns a value. There are two ways to use this operator: as pre increment ++i (returns the value before incrementing) or post increment i++ (returns the value after incrementing). Both variants are useful. When used on a single line (like in your example) it doesn't matter. You can also write it as i = i + 1 or using the addition assignment i += 1.
let value = 0;
console.log( 'Pre increment: before %d, result %d, after %d', value, ++value, value); // before 0, result 1, after 1
value = 0;
console.log( 'Post increment: before %d, result %d, after %d', value, value++, value); //before 0, result 0, after 1
Using the while-statement is one way to create the loop that iterates over the string, using the for-statement is another, more compact way.
Example with while:
let i = 0; // initialization
while ( i < string.length ) { // check contition
// ... some code ...
i += 1;
}
Example with for:
for ( let i = 0; i < string.length; i += 1 ) {
// ... some code ...
}
The pros with for are: the initialization, condition and final expression is defined in the header. The scope of the i variable can with let be restricted to be defined only inside the for-loop.
Your example, but with a for-loop:
function countChars(string, character) {
let count = 0; // set variable count to zero
for (let i = 0; i < string.length; i += 1) {
if (string[i] === character) { // check character at position i
count++; // Increment count by one
}
}
return count; // returns count
}
console.log("Count", countChars("ABCDABC", "A"));
The code is buggy!
There is a bug with this solution, and it has to do with how characters are defined. In Javascript each position of the string is a 16-bit integer. It works for most text, but fails for emojis and other characters that aren't in the Unicode Basic Multilingual Plane since they are defined with two positions in the string (surrogate pairs).
A solution that works is to use the split-method, that splits a string object into an array of strings, using a specified separator string to determine where to make each split. Note that if the separator string isn't found, or if the input string is empty, an array of one string will be returned. If there is one match, the returned array will have two strings. So the split-method returns a value that is one more than what we want, but that is easy to fix by just subtracting one.
function countChars(string, character) {
return string.split(character).length - 1;
}
console.log("Count", countChars("ABCD😃ABC😃", "😃"));
Optimizations
While “Premature optimization is the root of all evil”, there are some things that can be written in a clean and optimized way while you write the code. For example, if you are writing to a file, it is very inefficient to open the file, write something, and then close the file inside the loop:
for( i = 0; i < array.length; i + i = 1) {
fs.openFile("log.txt").write(array[i]).close();
}
It should be no surprise that it is more efficient to first open the file, write inside the loop, and then close the file:
fh = fs.openFile("log.txt");
for( i = 0; i < array.length; i + i = 1) {
fh.write(array[i]);
}
fh.close();
The reason I mention this, is because when I write a for-statement, I usually initialize both the variable and the length in the initialization part of the for-statement, since the length of the string doesn't change (and using the property string.length is always more expensive than using a local variable).
for (let i = 0, length = string.length; i < length; i += 1) {
// ... code ...
}
Another thing: string[i] and string.charAt(i) creates a new string in every iteration of the loop. To compare a single character inside a loop, it is much faster to compare integers instead of strings, by using string.charCodeAt(i). And instead of string.charCodeAt(i) you can use string.codePointAt(i) to make it safe to use with all Unicode characters like emoji, not only the characters in the BMP.
As I said above, the method that you used isn't safe to use with Unicode. For example, if you search for an emoji (😃), you will not get the correct result.
The following two methods are safe to use with all Unicode codepoints. Both of them can handle a needle with multiple characters.
function count_split(haystack, needle) {
return haystack.split(needle).length - 1;
}
This function uses a regular expression as the needle, and that can give unexpected results, since some characters have special meaning. For example, if you search for a dot (.) it will match every character. On the other hand, you can do an advanced search for '[ab]' that will match all 'a' and 'b' characters.
function count_match(haystack, needle) {
const match = haystack.match(new RegExp(needle, 'g')) || [];
return match.length;
}
The following method is safe to use with any Unicode, and the needle must be a single codepoint.
function countChars(haystack, needle) {
let count = 0;
const codePoint = needle.codePointAt(0);
if (
!((needle.length === 1) || (needle.length === 2 && codePoint > 0xffff))
) {
// NOTE: Using charPointAt(0) returns the codePoint of the first character.
// Since the characters in the string is stored as 16-bit integers,
// characters outside of the Unicode BMP is stored as surrogate pairs
// in two positions. Thats why the length of the string is1 for
// a BMP codepoint and 2 for a codepoint outside of the BMP.
// codePointAt handles the decoding of the surrogate pair.
throw Error('needle should be one codepoint');
}
for (let i = 0, length = haystack.length; i < length; i += 1) {
if (haystack.codePointAt(i) === codePoint) {
count++;
}
}
return count;
}
I have created test-cases on jsperf.com to compare the speed of the Unicode safe-functions mentioned above, and also the UNSAFE-functions that where published in this thread while I was writing this answer.
Without slice
function countChars(string, character) {
let count = 0;
let i = 0;
while (i < string.length) {
if (string[i] === character) {
count++;
}
i++;
}
return count;
}
console.log(countChars('foobar', 'o'))
With slice, but without i.
function countChars(string, character) {
let count = 0;
while (string.length) { // check if the length is not zero
if (string[0] === character) {
count++;
}
string = string.slice(1); // take the rest of the string, beginning from index 1
}
return count;
}
console.log(countChars('foobar', 'o'))
If you're willing to look for other solutions, here is a short one.
function count(str, char){
let count = str.split('').filter(c => {
return c.toLowerCase() === char.toLowerCase()
});
return count.length;
}
console.log(count('hello world', 'l'));
Note: The above solution is case-insensitive.
I would do it like this
function countChars(string, character) {
return string.split('').filter(e => e === character).length;
}
console.log(countChars('foobar', 'o'))
But #bambam RegEx approach is likely the most efficient.
A shorter version :)
function count(string,char) {
return string.split('').filter(x => x === char).length;
}
Thanks
How to get the number before 'x'?
I tried using .split('x')[0] but it grabs everything before 'x'.
123x // Gives 123
123y+123x - // Gives 123
123x+123x - // Gives 246
I've tested a function which uses regex that I think will work. I've included the results, an explanation of how the function works, and then a commented version of the function.
Note, this doesn't handle any algebra more complex than adding and subtracting simple terms. I would refer to https://newton.now.sh/ for that, it's an API which can handle simplification (I am not affiliated).
Results:
console.log(coefficient("-x+23x")); // 22
console.log(coefficient("123y+123x")); // 123
// replaces spaces
console.log(coefficient("x + 123x")); // 124
console.log(coefficient("-x - 123x")); // -124
console.log(coefficient("1234x-23x")); // 1211
// doesn't account for other letters
console.log(coefficient("-23yx")); // 1
Explanation:
First the function removes spaces. Then it uses a regex, which finds any sequence of numbers that are followed by an 'x'. If there's a +/- in front, the regex keeps that. The function loops through these sequences of numbers, and adds them to a total. If there's an 'x' that does not have numbers with it, its coefficient is assumed as -1 or 1.
Commented Code:
function coefficient(str) {
// remove spaces
str = str.replace(/\s/g, '');
// all powerful regex
var regexp = /(\+|-)?[0-9]*x/g
// total
sum = 0;
// find the occurrences of x
var found = true;
while (found) {
match = regexp.exec(str);
if (match == null) {
found = false;
} else {
// treated as +/- 1 if no proceeding number
if (isNaN(parseInt(match[0]))) {
if (match[0].charAt(0) == "-") {
sum--;
} else {
sum++;
}
// parse the proceeding number
} else {
sum += parseInt(match[0]);
}
}
}
return sum;
}
I don't know if there is sufficient cleverness in ECMAScript regular expressions to do look behind, but you can do it with match and post processing to remove the "x".
If the intention is to sum the terms, then a further operation with reduce is required. Trimming the x could be combined with reduce so that map isn't required.
console.log(
'123x+123x'.match(/\d+x/ig).map(function(v){
return v.slice(0,-1)
}).reduce(function(sum, v){return sum + +v},0)
);
console.log(match('123x+123y+456x', 'x'))
console.log(match('123x+123y+456x', 'y'))
function match(str, x) {
return str.match(new RegExp('\\d+' + x, 'g')).reduce((cur, p) => {
return cur + parseInt(p.substr(0, p.length - x.length))
}, 0)
}
My whole goal was to write a loop that would take a string, count the letters and return two responses: one = "this word is symmetric" or two = "this word is not symmetric". However the code I wrote doesn't console anything out. Here's the code:
var arya = function(arraycount){
for (arraycount.length >= 1; arraycount.length <= 100; arraycount++) {
while (arraycount.length%2 === 0) {
console.log("This is a symmetric word and its length is " + " " arraycount.length " units.");
arraycount.length%2 != 0
console.log("Not a symmetric word");
}
}
}
arya("Michael");
There are many ways to accomplish your goal, but here are a few. The first is a somewhat naïve approach using a for loop, and the second uses recursion. The third asks whether the string equals the reverse of the string.
iterative (for loop) function
var isPalindromeIteratively = function(string) {
if (string.length <= 1) {
return true;
}
for (var i = 0; i <= Math.floor(string.length / 2); i++) {
if (string[i] !== string[string.length - 1 - i]) {
return false;
}
}
return true;
};
This function begins by asking whether your input string is a single character or empty string, in which case the string would be a trivial palindrome. Then, the for loop is set up: starting from 0 (the first character of the string) and going to the middle character, the loop asks whether a given character is identical to its partner on the other end of the string. If the parter character is not identical, the function returns false. If the for loop finishes, that means every character has an identical partner, so the function returns true.
recursive function
var isPalindromeRecursively = function(string) {
if (string.length <= 1) {
console.log('<= 1');
return true;
}
var firstChar = string[0];
var lastChar = string[string.length - 1];
var substring = string.substring(1, string.length - 1);
console.log('first character: ' + firstChar);
console.log('last character: ' + lastChar);
console.log('substring: ' + substring);
return (firstChar === lastChar) ? isPalindromeRecursively(substring) : false;
};
This function begins the same way as the first, by getting the trivial case out of the way. Then, it tests whether the first character of the string is equal to the last character. Using the ternary operator, the function, returns false if that test fails. If the test is true, the function calls itself again on a substring, and everything starts all over again. This substring is the original string without the first and last characters.
'reflecting' the string
var reflectivePalindrome = function(string) {
return string === string.split('').reverse().join('');
};
This one just reverses the string and sees if it equals the input string. It relies on the reverse() method of Array, and although it's the most expressive and compact way of doing it, it's probably not the most efficient.
usage
These will return true or false, telling you whether string is a palindrome. I assumed that is what you mean when you say "symmetric." I included some debugging statements so you can trace this recursive function as it works.
The Mozilla Developer Network offers a comprehensive guide of the JavaScript language. Also, here are links to the way for loops and while loops work in JS.