Javascript - Removing last 3 words from a string - javascript

I've been able to find examples of how to remove the last word of a string, but in this instance I'm attempting to remove the last 3 words of a string. I've attempted this by adjusting some of the answers I've come across to remove a single word but none have gave me the expected results.
Example string Highest ranked in the states
I would like my return value be Highest ranked
Here are some code snippets of what I've attempted:
let myString = "Highest ranked in the states";
myString = myString.substring(2, myString.lastIndexOf(" "));
console.log(myString)
let myString2 = "I want to remove the last word";
let mySplitResult2 = myString2.split(" ");
let lastWord = mySplitResult2[mySplitResult2.length-3]
console.log(lastWord)
with the adjusting the substring method to (2, myString.lastIndexOf(" ")); it ended up removing the first two letters of my sentence and only removed the word states such as "guest ranked in the"
when adjusting the .split() method to length -3 it simply returns back the word in instead of in the states

Here is a nice and readable one liner:
const remove3words = words => words.split(" ").slice(0, -3).join(" ");
console.log(remove3words("Highest ranked in the states"));
console.log(remove3words("Exactly three words"));
You can generalize it easily to n words in the following way:
function remove_n_words(words, n) {
return n === 0 ? words : words.split(" ").slice(0, -n).join(" ");
}
// Test the function
console.log(remove_n_words("Highest ranked in the states", 0));
console.log(remove_n_words("Highest ranked in the states", 3));
console.log(remove_n_words("Highest ranked in the states", 100));

let myString = "Highest ranked in the states";
myString = myString.split(' ')
myString = myString.splice(myString.length-5,2)
myString = myString.join(' ')
console.log(myString)

See comments for explanation using split and splice
let myString = "Highest ranked in the states";
//split the str using blank space between each word and add to new variable
let str = myString.split(" ");
//get the length
let num = str.length;
//splice the array removing the last three values with the number - 3
let newStr = str.splice(0, num - 3);
let displayText = '';
//back into string
newStr.forEach(function(value){
displayText += value + ' ';
});
display.textContent = displayText;
<div id="display"></div>

Here's a function that can do that for you. (It can actually remove all characters from the Nth-to-last occurrence of any character you specify, not just the Nth-to-last word.)
In your case:
the char parameter should get the value ' ' (ie spaces between words)
N should get the value 3 (to target the 3rd-to-last space)
I added an excludeChar parameter that you can set to true to avoid returning the final space (or you can use the .trim method on the result).
const
myString = "Highest ranked in the states",
result = truncateAtNthToLastOccurencOfChar(myString, ' ', 3);
console.log(result);
function truncateAtNthToLastOccurencOfChar(str, char, N, excludeChar){
// Makes counter, converts str to arr & reverses it
let i = -1, rev = Array.from(str).reverse();
// Increments counter (and executes even when i=0)
while(++i || true){
// Returns original string if at the end `char` has occured fewer than `N` times
if(i >= rev.length - 1){
return str;
}
// If current character matches `char`, decrements `N`
if(rev[i] == char && --N === 0){
// If N=0, `i` is our target, all keeps characters (from reversed array)
// starting at `i` (or after `i` if excludeChar=true)
return rev
// The occurence of char can be excluded from result
.slice(excludeChar ? (i + 1) : i)
.reverse() // Restores original character order
.join(''); // Converts back to string
}
}
}

Related

vowelFrequency JavaScript function

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;
}

Insert Spaces into string at an index

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"));

How to create a letter scoring function that scores vowels differently from consonants

So I'm trying to create a word scoring algorithm that gives one point for every consonant and 3 point for every vowel. But every attempt I've tried has failed which means something isn't mentally clicking for me and I need help understanding what I'm doing wrong
I've searched all over the web and found numerous ways to check letters of a word and count vowels, which I've tried customizing and using for my scoring algorithm and I still keep getting the wrong scoring output when testing each approach. I've looked at using iterative approached and using regular expressions. Someone was telling me that my fault is in my second loop but I'm not sure how to correct it.
//The attempt where apparently the second loop is the problem:
vowelBonus= (word)=>{
let score = 0;
const vowels = ["a","e","i","o","u"];
word = word.toLowerCase();
for (letter in word){
vowels.forEach((value)=>{
if (letter === value){
score += 3
}else if(letter !== value){
score += 1
}
})
return score
}
}
// An attempt using a regular expression which I kind of prefer after reading up on them
vowelBonus = (word)=>{
let vowel = word.match(/[aeiou]/gi);
let vCount = 0
let consCount = 0
let score = vCount + consCount
if(vowel.length){
vCount += 3
}else if (!vowel.length){
consCount =+ 1
}
return score
}
//I have about 3-5 other versions I've toyed around with but I'd like to stay in the ballpark of something like the two snippets I've pasted above.
//One version keeps giving an output of 0. Another gives increments of 5, and I've had a few give a result of 1-5. I'm expecting the result to be 1pt for every consonant and 3pts for every vowel. Meaning if I type in the word "code", the result should be 8pts.
EDIT: Don't forget about edge cases, like if someone supplies a space in the word... Just something to consider...
EDIT 2: Added example using regex that ignores spaces if they are supplied..
Something like this should work.. I find it easiest to use the Array.includes method for things like this.
Let me know if you have any questions!
function scoreWord(word) {
// Ignores spaces
return word.replace(/\s/g,'').toLowerCase().split("").reduce((a, i) =>
a += ["a", "e", "i", "o", "u"].includes(i) ? 3 : 1, 0);
}
function scoreWordSimplified(word) {
// Ignores spaces; Simplified example
let wordArray = word.replace(/\s/g, "").toLowerCase().split("");
let vowels = ["a", "e", "i", "o", "u"];
let pointsForVowel = 3;
let pointsForConsonant = 1;
let finalScore = 0;
wordArray.forEach(letter => {
if (vowels.includes(letter)) {
finalScore += pointsForVowel;
} else {
finalScore += pointsForConsonant;
}
/** Or you could do:
* finalScore += vowels.includes(letter) ? pointsForVowel : pointsForConsonant;
*/
});
return finalScore;
}
let vowelBonus = (word)=>{
// credit: #Code Maniac
// Ignores spaces
let _word = word.replace(/\s/g,'');
let vowel = _word.match(/[aeiou]/gi);
let wordLength = _word.length;
let vowelLength = vowel && vowel.length;
return vowel ? (wordLength - vowelLength) + vowelLength *3 : wordLength
}
let score1 = scoreWord("some word");
let score2 = vowelBonus("some word");
let score3 = scoreWordSimplified("some word");
console.log("scoreWord: ", score1);
console.log("vowelBonus: ", score2);
console.log("scoreWordSimplified: ", score3);
It's simpler with regex:
(word)=>{
let vowel = word.match(/[aeiou]/gi);
vowelScore = 3 * vowel.length
consScore = word.length - vowel.length
return vowelScore + consScore
}
Well there are lots of problems to notice in you code.
In example 1
Do not use for .. in for looping over the strings,
when you iterate over string using for ... in it returns the index ( key ) of string not the value.
You're returning value inside for...in after first iteration itself, whereas you need to return value after loop,
Inside the loop you're looping over the vowels everytime and if the value is found you're adding 3 if not found you're adding 1, but for each single characters you're looping on vowels which adds extra count than it should
In example 2
You're matching with regex and than if the length is greater than zero you're adding value just once whereas it should be match.length * 3 and for the remaining length it should be (word.length - match.length)
so you can simply do this
let vowelBonus = (word)=>{
let vowel = word.match(/[aeiou]/gi);
let wordLength = word.length
let vowelLength = vowel && vowel.length
return vowel ? (wordLength - vowelLength) + vowelLength *3 : wordLength
}
console.log(vowelBonus("aeiou"))
console.log(vowelBonus("abcd"))
console.log(vowelBonus("aeibcd"))

JavaScript string converting to lower or uppercase

//1. input words beginning and ending with a vowel are preserved in lowercase
//2. input words beginning with vowels and ending in a non vowel are translated to uppercase
//3. input words beginning with a non vowel and ending with a vowel are translated to a capitalized word (only first letter is uppercase)
//4. when printing the words, only two vowels are preserved per word (the first two)
//Output "i dont know Dude i AM not typing ALL OF this Nonsens text"
var str = "i dont know dude i am not typing all of this nonsense text";
console.log(str);
var res = str.split(" ");
console.log(res);
for(let i = 0; i<res.length;i++){
//checking words after spliting into single words
if((res[i].split("") && (res[0] ==== 'a'|| 'e' || 'o' || 'u' || 'i' || 'y') && (/* last charachter to check */ ))
}
I am beginner JavaScript Developer and i am having some difficulties with my exercise i have above 4 conditions first i split the array into a words then i hoped to split into single characters so res[0] will be my first item . I dont know if this will work but at least i need to try. Any help will be very appreciated even if it is with regular expressions. Thank you
You can use reduce of Array.prototype.
var str = "i dont know dude i am not typing all of this nonsense text";
console.log(str);
var res = str.split(" ");
var y=res.reduce((a,e) => {
if("aeiou".includes(e[0])){ //condition 1 and 2
return a + ("aeiou".includes(e[e.length-1]) ? getWord(e).toLowerCase() : getWord(e).toUpperCase()) + " ";
}
else{ //condition 3
return a + ("aeiou".includes(e[e.length-1]) ? e[0].toUpperCase() + getWord(e.substr(1)).toLowerCase() : e) + " ";
}
},"");
function getWord(x){ //condition 4
var count = 0;
for(var i = 0; i < x.length; i++){
count += "aeiou".includes(x[i]) ? 1 : 0;
if(count === 3)
return x.substr(0,i);
}
return x;
}
console.log(y);
Here is a quick function that does fulfills 1 to 3. I'm not sure what you mean in 4.
Snippet:
/* Example. */
var str = "i dont knoooow dudeeeee i am not typing all of this nonsense text";
console.log(str);
console.log(process(str));
/* --------------------------------------------- */
/* The function that checks whether a char is a vowel. */
function isVowel (char) {
return "aeiou".includes(char);
}
/* The function that truncates a word before the 3rd vowel. */
function truncate (word) {
/* Create an index and a counter and save the length of the word. */
var i = 0, c = 0, l = word.length;
/* Iterate over every char until 3 vowels are found, if found. */
for (; i < l && c < 3; i++, c += +isVowel(word[i]));
/* Return the part of the string until before the 3rd vowel. */
return word.slice(0, i);
};
/* The function that processes the string. */
function process (str) {
/* Split the sentence into an array of words. */
var words = str.split(" ");
/* Iterate over every word. */
words.forEach(function (word, index) {
/* Strip any more than 2 repeated vowels and anything beyond the 3rd vowel. */
word = truncate(word.replace(/([aeiou])\1{2,}/i, "$1$1")); // 4
/* Check whether the first character is a vowel or not. */
words[index] = isVowel(word[0])
/* Check whether the last character is a vowel or not. */
? isVowel(word[word.length - 1])
? word.toLowerCase() // 1
: word.toUpperCase() // 2
/* Check whether the last character is a vowel or not. */
: isVowel(word[word.length - 1])
/* Capitalise the first char and turn the rest to lowercase. */
? word[0].toUpperCase() + word.slice(1).toLowerCase() // 3
: word;
});
/* Join the array into a string and return it. */
return words.join(" ");
}
res[0] ==== 'a'|| 'e'
That wont work. You need to do:
res[0] ==== 'a'|| res[0] === 'e'
However as that is quite complicated, might just do:
"aeiou".includes(res[0])
Oh and res[0] is the first word, not the first char, that would be res[i][0]. And you can get the last one with res[i][res[i].length - 1]. And i still dont get what you are trying to do with res[i].split("") && ... just leave that away.

JS toLowerCase() not working

I have this code :
//make first letter of each word capital
function titleCase(str) {
/*
* 1. change all letters to lower case
* 2. split words
* 3. set each 1st letter to Capital
* 4. combine array back into string
*/
arr = [];
str.toLowerCase();
arr = str.split(" ");
for (var index = 0; index < arr.length; index++) {
arr[index].charAt(0).toUpperCase();
}
str= arr.join(" ");
return str;
}
console.log(titleCase("Potato potato potato"));
And I don't understand why toLowerCase() and toUpperCase() are not working. What am I doing wrong ?
There are 2 updates required
Reassign str.toLowerCase() to str
Reassign updated array value back in array.
Please note, until and unless you reassign the values, the original value does not change. Hence, the result remained unaffected.
//make first letter of each word capital
function titleCase(str) {
/*
1. change all letters to lower case
2. split words
3. set each 1st letter to Capital
4. combine array back into string
*/
arr = [];
str = str.toLowerCase(); // **** Problem 1 - Reassigning
arr = str.split(" ");
for (var index = 0; index < arr.length; index++) {
// **** Problem 2 - Reassigning
arr[index] = arr[index].charAt(0).toUpperCase() + arr[index].slice(1);
}
str= arr.join(" ");
return str;
}
console.log(titleCase("Potato potato potato"));
You need to reassign (overwrite) the value inside the array after you change it. Otherwise, the array remains unchanged. Besides, you forgot to add the rest of the string (arr[index].slice(1)) to the uppercased letter.
function titleCase(str) {
let arr = [];
str.toLowerCase();
arr = str.split(" ");
for (var index = 0; index < arr.length; index++) {
arr[index] = arr[index].charAt(0).toUpperCase() + arr[index].slice(1); // <-- Changes
}
str= arr.join(" ");
return str;
}
console.log(titleCase("Potato potato potato"));
EDIT
Here is my own ES6 one-liner version :
titleCase = str => str.trim().split(" ").map( word => word.charAt(0).toUpperCase() + word.slice(1) ).join(" ")
console.log(titleCase("Potato potato potato"));
Explanation :
titleCase = str => str
.trim() // Removes extra spaces
.split(" ")
.map( word =>
word.charAt(0).toUpperCase() + word.slice(1) // Uppercases 1st letter, adds the rest of the word, returns the whole
)
.join(" ") // Reforms a string
you can simply do
function convert(str){
return str.split(' ').map(e => e.replace(/([A-Za-z])(\w+)/, (x, y, z) => y.toUpperCase()+z.toLowerCase())).join(' ');
}
console.log(convert('Potato potato pOtato'))
short solution:
var titleCase = (str)=>str.toLowerCase().split(' ').map(word=>word.charAt(0).toUpperCase()+word.slice(1)).join(' ');
calling:
titleCase('Potato potato potato');
Splitting the string by space and map a lambda to the resulting array. The lambda turns up the first letter and append the rest of the word.
as pointed out in the comments:
var titleCase = (str)=>str.toLowerCase().split(' ').reduce((currentString, word)=>currentString+(currentString ? ' ':'')+word.charAt(0).toUpperCase()+word.slice(1));
this works also and loops only one time.

Categories

Resources