Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 23 days ago.
Improve this question
I've this piece of code that will count the number of occurrences found in a given string.
But it will only count the number of unique special characters in the string.
How can I change this behavior ?
It should give me 3 and not 1 as I have 3 spaces.
Thanks.
var string = 'hello, i am blue.';
var specialChar = [' ', '!'];
let count = 0
specialChar.forEach(word => {
string.includes(word) && count++
});
console.log(count);
What you are doing is iterating over specialChar, which yields two iterations: the first iteration will check if ' ' is included in the string which is true and thus increments count, and the second iteration will check if '!' is included in the string which is not the case hence you get 1.
What you should actually do is iterate through the string and check if each character is included in the specialChar array. Here is how you can do that with the minimum changes made (the code can be improved and made clearer).
Note: .split("") splits the string to an array of its characters.
var string = 'hello, i am blue.';
var specialChar = [' ', '!'];
let count = 0
string.split("").forEach(char => {
specialChar.includes(char) && count++
});
console.log(count);
Since you're using an array of matches [" ", "!"] you need as an output - and Object with the counts, i.e: {" ": 5, "!": 2}.
Here's two examples, one using String.prototype.match(), and the other using Spread Syntax ... on a String
Using Match
and Array.prototype.reduce() to reduce your initial Array to an Object result
const string = 'hello, i am blue. And this is an Exclamation! Actually, two!';
const specialChar = [' ', '!'];
const regEscape = v => v.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
const count = specialChar.reduce((ob, ch) => {
ob[ch] = string.match(new RegExp(regEscape(ch), "g")).length;
return ob;
}, {}); // << This {} is the `ob` accumulator object
console.log(count);
Using String spread ...
to convert the string to an array of Unicode code-points sequences / symbols
const string = 'hello, i am blue. And this is an Exclamation! Actually, two!';
const specialChar = [' ', '!'];
const count = [...string].reduce((ob, ch) => {
if (!specialChar.includes(ch)) return ob;
ob[ch] ??= 0;
ob[ch] += 1;
return ob;
}, {}); // << This {} is the `ob` accumulator object
console.log(count);
One way to count characters in a string is to split the string by the character and then count the parts and subtract one.
var string = 'hello! i am blue!';
var specialChar = [' ', '!'];
let count = 0
specialChar.forEach(char => {
count += string.split(char).length - 1
});
console.log(count);
Or using RegExp being sure to escape anything that is considered a special character.
function escapeRegex(v) {
return v.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
function countChars(str, chars) {
const escapedChars = escapeRegex(chars.join(''));
const regex = new RegExp(`[${escapedChars}]`, "g");
return str.match(regex)?.length || 0;
}
console.log(countChars('hello! i am blue!', [' ', '!']));
The fastest version turns out to be one that counts the char in a word using indexOf
function countCharsIndexOf(str, char) {
let num = 0;
let pos = str.indexOf(char);
while (pos > -1) {
pos = str.indexOf(char, pos + 1);
num++;
}
return num;
}
function countAllCharsIndexOf(str, chars) {
return chars.reduce(
(acc, char) => acc + countCharsIndexOf(str, char),
0
);
}
console.log(countAllCharsIndexOf('hello! i am blue!', [' ', '!']));
Related
I need to iterate over an input string and return a string with the count of the frequency of the different vowels in the string. The vowels in the return string should be in the order they appear in the input string. So, if 'hello world' is the function's parameter, the function should return e1o2. The code I have so far is below. It returns e1o2o3. For some reason, it is not stopping the count of o after it hits the o in hello, and seems to be counting the o in world as a separate count. I think it is, finalString += char + sum;, that is causing this. But, I do not know how to create this function in the first place. Thank you for your time.
function vowelFrequency(str) {
let finalString = '';
let sum = 0;
for (let char of str) {
if ('aeiou'.includes(char)) {
sum += 1;
finalString += char + sum;
}
}
return finalString;
};
The main problem is your sum counter. It counts all vowels together.
Better appoach would be to create a dictionary of vowels
where we add +1 every time we met a match.
In short the idea is:
if (char === 'e') {
dic['e'] += 1;
}
const text = 'hello world';
function vowelFrequency(str) {
let finalString = '';
let dic = {};
for (let char of str) {
if ('aeiou'.includes(char)) {
//check if dictionary has no certain vowel
//it happens when we first time meet a vowel
if (!(char in dic)) {
dic[char] = 0;
}
//increment our counter
dic[char]+=1;
}
}
//by the end of the loop
//we have object with { e: 1, o: 2 }
//now we need to gather values into string
//loop through the object
for ([char, count] of Object.entries(dic)) {
finalString += char + count;
}
return finalString;
};
console.log(vowelFrequency(text));
Shorter version of the same solution would be:
function vowelFrequency(str) {
const vowels = 'aeiou';
let dic = [...str].reduce((dic, char) => {
if (vowels.includes(char))
dic[char] = dic[char] + 1 || 1;
return dic;
}, {});
return Object.entries(dic)
.map(([char, count]) => `${char}${count}`)
.join('');
};
One concise approach would be to transform the string via String.prototype.replaceAll (evaluating every character in the string). The following code searches the original string (which you may wish to normalize beforehand with .toLowerCase() for better results) for any character.
"hello world".replaceAll(/./g, ( char, index, str ) =>
!'aeiou'.includes( char ) || str.lastIndexOf( char ) > index
? "" : char + [ ...str ].filter( o => o == char ).length
);
Each character is checked against a list of vowels. We also check to see if the character index is the last index of this character (does it appear multiple times) in the original string. If either of these conditions fail, an empty string is returned in the character's place.
If our character is in our vowel list, and is the last instance of itself, then we split the original string, filter-out non-matching characters, and return the final count of character instances.
The above approach is somewhat of a gimmick. It's concise, but probably not very self-explanatory or maintainable. Realistically, you'd want to take a slightly more verbose approach (see below).
Note that Map is preferred over a standard object to ensure that key-insertion order is preserved.
function charInstanceString ( input, chars = "aeiou" ) {
/**
* Cycle over each character in our string, checking
* if it appears in our `chars` string. If the character
* appears in our `chars` string, we'll update our map
* to reflect the number of instances for the character.
*/
const charMap = new Map();
for ( const char of input ) {
if ( !chars.includes( char ) ) continue;
charMap.set( char, charMap.get( char ) + 1 || 1 );
}
/**
* Cycle over our map, adding each character (and its
* corresponding count) to an output string.
*/
let output = "";
for ( const [ char, count ] of charMap ) {
output += `${ char }${ count }`;
}
return output;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 months ago.
Improve this question
I need to implement a splitString function that takes a string str, divides it into parts of 2 characters each, and then returns an array of those parts.
If the string contains an odd number of characters, I need to add a '_' after the last character.
For example:
splitString('123456'); *// ['12', '34', '56']*
splitString('ab cd ef'); *// ['ab', ' c', 'd ', 'ef']*
splitString('abc'); *// ['ab', 'c_']*
splitString(' '); *// [' _']*
splitString(''); *// []*`
function splitString(str) {
const result = [];
for (let i = 0; i < str.length; i += 2) {
if (str % 2 === 0) {
result.push(str.substring(i, i + 2));
}
if (str % 2 !== 0) {
}
}
return result;
}
There's a few ways to do this. First, with your approach, I'd suggest only doing the padding once, not one every iteration.
Also str % 2 probably isn't what you want, but rather str.length % 2
function splitString(str) {
const result = [];
// force it to be even-length, padding if necessary
if (str.length % 2 !== 0) {
str = str + "_";
}
for (let i = 0; i < str.length; i += 2) {
result.push(str.substring(i, i+2));
}
return result;
}
console.log(splitString("abc"));
console.log(splitString("abcd"));
console.log(splitString(""));
Another option is to use a regular expression
function splitString(str) {
if (str.length % 2 !== 0) str += "_";
// str.split will return an array like
// ["", "ab", "", "cd"]
// so we use `.filter` to remove the empty elements
return str.split(/(..)/g).filter(s => s)
}
console.log(splitString("abc"));
console.log(splitString("abcd"));
I would do it with a different approach - using the rest and spread operators with a while loop.
Also, I suggest that the 0 length string be short circuited, as its result is always the same ([] - an empty array).
const strings = [
'123456',
'ab cd ef',
'abc',
' ',
'',
]
const splitString = (str) => {
if (!str.length) return []
let arr = [...str] // creating a local variable
let ret = [] // creating the return variable
while (arr.length) {
// destructuring the two characters
const [first, second = "_", ...rest] = arr
// adding the new items to the return array
ret = [...ret, "" + first + second]
// modifying the local variable, so on the next "while"
// run it's updated
arr = rest
}
return ret
}
const c = strings.map(splitString)
console.log(c)
first time posting. I'm writing a function in js that reverses words with more than 5 characters in a given string. It works, but I think it is adding extra "space" strings that it doesn't need if the string inputted is only one word. I know I have too many variables and there is a way better way to do this. I'm pretty new to this, but anything helps. Thanks!
const exString = "Hey fellow warriors"
function spinWords(string){
let newWord = string.split(' ');
let fiveWord = "";
let lessWord = "";
for(i=0; i<newWord.length;i++){
if(newWord[i].length >=5){
fiveWord += newWord[i].split('').reverse() + ' ';
}
else{
lessWord += newWord[i]
}
}
newFiveWord = fiveWord.replace(/,/g,'');
return lessWord + ' ' + newFiveWord
}
console.log(spinWords(exString));
const spinWords = str => str
.split(' ')
.map(word => word.length >= 5
? [...word].reverse().join('')
: word)
.join(' ')
console.log(spinWords("Hey fellow warriors"))
Turn the string into an array of words
Modify each word. If 5+ letters: [..word] turns the string into an array of letters ('hi' > ['h', 'i']). Then reverse the array, and turn the letters back into one string.
Undo step one by turning the array into one string.
function reversedText() {
let text = prompt("Enter text");
const words = text?.split(" ");
const newText = words.map((word) => {
if (word.length >= 5) {
return (word.split("").reverse().join(""));
}
return word;
});
if (newText.length > 0) {
return newText.filter(notNull).join(" ");
} else {
return 'Your sentence have words which have length less than 5';
}
}
function notNull(value) {
return value != null
}
console.log(reversedText());
I'm trying to do this Codewars problem.
Task
In this simple Kata your task is to create a function that turns a string into a Mexican Wave. You will be passed a string and you must return that string in an array where an uppercase letter is a person standing up.
Rules
The input string will always be lower case but maybe empty.
If the character in the string is whitespace then pass over it as if it was an empty seat.
Example
wave("hello") => ["Hello", "hEllo", "heLlo", "helLo", "hellO"]
My code so far is hosted on this repl.it
My thought process is as follows:
Turn argument into array
manipulate each index of the array at index and then readjust previous index to make a wave pattern
turn array into string
reinsert spaces before logging it to console and restarting the loop
I'm pretty stuck and my mind is stuck on how to use
for(var j = 0; j < indexSpaceNumber.length; j++){
//join and add in the spaces at their former index before returning string
strToArray[indexSpaceNumber[j]].slice(0, " ");
}
to insert the spaces into the string.
If there's any guidance or tips it would be much appreciated. I feel like I'm close, but so frustratingly far.
The main idea would be:
Iterate the characters
Replace the character in the original string with an uppercase version
You can use Array.from() to convert the string to an array, and map each item to a new string. If the character is a space return something falsy (en empty string in the example). After the creating the array, filter all falsy values:
const wave = str =>
Array.from(str, (c,i) => // convert the string to an array
// replace the character with an uppercase version in the original string
c === ' ' ?
''
:
`${str.substring(0, i)}${c.toUpperCase()}${str.substring(i + 1)}`
).filter(c => c)
const result = wave("hello")
console.log(result)
For string with spaces
function wave(str) {
let res = []
str.toLowerCase().split('').forEach((v, i) => {
if(v == ' ') return;
res.push( str.substr(0, i) + v.toUpperCase() + str.substr(i + 1) )
});
return res
}
console.log(wave("hello hello"))
I'd go recursive ;)
You know that for a string of length n you need an array of the same length. That's your exit condition.
You can use the length of the array at each iteration to work out the shape of the next string:
hello [] [Hello] 0: uppercase 1st char and append
hello [Hello] [Hello hEllo] 1: uppercase 2nd char and append
hello [Hello hEllo] [Hello hEllo heLlo] 2: uppercase 3rd char and append
...
const wave =
(str, arr = []) =>
str.length === arr.length
? arr
: wave
( str
, [ ...arr
, str.slice(0, arr.length)
+ str[arr.length].toUpperCase()
+ str.slice(arr.length + 1)
]
);
console.log(wave('hello'));
Go over each char in string and build
Slice str from start till current char + current char to upper case + Slice str from current char to end
const wave = str => {
const res = [];
for (let i = 0; i < str.length; i++) {
res.push(`${str.slice(0, i)}${str[i].toUpperCase()}${str.slice(i + 1)}}`);
}
return res;
};
console.log(wave("hi my name is rylan"));
// Alternate way to do with Array.splice
const wave2 = str => {
const res = [];
for (let i in str) {
const temp = Array.from(str);
temp.splice(i, 1, temp[i].toUpperCase());
res.push(temp)
}
return res.map(x => x.join(''));
};
console.log(wave2("hi my name is rylan"));
I am trying to create a function that takes in a string and changes each letters value to a "(" if the character is not duplicated in the string, and a ")" if the character does have a duplicate present in the string. I have decided to go an unconventional route to solve this problem but I am running in to an issue with a double for loop. From what I understand, the inner for loop in javascript does not have access to the variables outside of the loop. I want to loop through every item in an array twice but I'm not sure what to set the inner loops length as.
Here is my code:
function sortAndChange(word) {
const splitter = word.toLowerCase().split("");
//let jSplitter = word.toLowerCase().split("").length;
let endResult = "";
let truthArray = [];
for(i = 0; i < splitter.length; i++){
for(j = 0; j < splitter.length; j++){
console.log(j);
if(splitter[i] == splitter[j]){
truthArray.push(true);
} else {
truthArray.push(false);
}
}
console.log(truthArray);
truthArray.every(item => item === false) ? endResult += "(" : endResult += ")";
truthArray = [];
}
console.log(endResult);
}
Expected Result:
sortAndChange("Success") //expected output: ")())())"
sortAndChange("easy") //expected output: "(((("
You can do that in following steps:
Convert string to array using split and use map() on it.
Compare the indexOf() and lastIndexOf() to check if its duplicate or not.
Return the ) or ( based on ur condition. And then at last join the array
function sortAndChange(str){
let arr = str.toLowerCase().split('')
return arr.map(x => {
//if its not duplicated
if(arr.indexOf(x) === arr.lastIndexOf(x)){
return '('
}
//If its duplicated
else{
return ')'
}
}).join('');
}
console.log(sortAndChange("Success")) //expected output: ")())())"
console.log(sortAndChange("easy")) //expected output: "(((("
You could take a object and keep a boolean value for later mapping the values.
This approach has two loops with O(2n)
function sortAndChange(word) {
word = word.toLowerCase();
var map = [...word].reduce((m, c) => (m[c] = c in m, m), {});
return Array
.from(word, c => '()'[+map[c]])
.join('');
}
console.log(sortAndChange("Success")); // )())())
console.log(sortAndChange("easy")); // ((((
This can easily be achieved using a combination of regex and the map construct in javascript:
const input = "this is a test";
const characters = input.toLowerCase().split('');
const transformed = characters.map(currentCharacter => {
const regexpression = new RegExp(currentCharacter, "g");
if (input.toLowerCase().match(regexpression || []).length > 1) return ')'
return '(';
}).join("");
console.log(transformed);
Look at the following snippet and comments
function sortAndChange(str) {
// we create an array containing the characters on the string
// so we can use Array.reduce
return str.split('').reduce((tmp, x, xi) => {
// we look if the character is duplicate in the string
// by looking for instance of the character
if (str.slice(xi + 1).includes(x.toLowerCase())) {
// Duplicate - we replace every occurence of the character
tmp = tmp.replace(new RegExp(x, 'gi'), ')');
} else {
// Not duplicate
tmp = tmp.replace(new RegExp(x, 'gi'), '(');
}
return tmp;
}, str);
}
console.log(sortAndChange('Success')); //expected output: ")())())"
console.log(sortAndChange('Easy')); //expected output: "(((("
1) use Array.from to convert to array of chars
2) use reduce to build object with key-value pairs as char in string and ( or ) as value based on repetition .
3) Now convert original string to result string using the chars from above object.
function sortAndChange(str) {
const str_arr = Array.from(str.toLowerCase());
const obj = str_arr.reduce(
(acc, char) => ((acc[char] = char in acc ? ")" : "("), acc),
{}
);
return str_arr.reduce((acc, char) => `${acc}${obj[char]}`, "");
}
console.log(sortAndChange("Success")); // ")())())"
console.log(sortAndChange("easy")); // ((((