begin .map(callback()) from specific index - javascript

Is it possible to run a callback function with specific start and stop indexes? I am practicing my JS and am writing a function to convert strings to camel case (from being '-' or '_' seperated) without altering the capitalization of the first word in the string. Basically, after I split the string into an array of words, I want to call .map() and start my callback on the second word in the array.
currently I have:
function toCamelCase(str){
return str.split(/\-|_/).map(word => word.charAt(0).toUpperCase() + word.slice(1)).join('');
}
How can I get .map() to begin at str.split(/\-|_/)[1] ?

In simple words, you can't. .map will iterate over an entire array.
You can chain .map to .slice though
function toCamelCase(str, start, stop){
return str.split(/\-|_/).slice(start, stop).map(word => word.charAt(0).toUpperCase() + word.slice(1)).join('');
}

Array.map() always iterates the entire array. You can use the index (2nd param in callback) to return the word without changes if the index is 0:
function toCamelCase(str){
return str.split(/\-|_/).map((word, i) => i ? word.charAt(0).toUpperCase() + word.slice(1) : word).join('');
}
console.log(toCamelCase('the_camels_toes'));
BTW - you can use a regular expression with String.replace() to to create the camel case:
function toCamelCase(str){
return str.replace(/_(\w)/g, (_, c) => c.toUpperCase());
}
console.log(toCamelCase('the_camels_toes'));

Related

Array manipulation error with regex - Kata 6 Codewar

In theory it should transform a given array to camel case. I don't understand what is wrong
function toCamelCase(str){
if(str.length === 0) return ""
let array = str.split(/([_-])/);
array.forEach(word =>{
word == "-" ? word.replace("") : word.charAt(0).toUpperCase()
})
return array
}
The .replace() method doesn't modify the word variable, it instead returns a new modified string. So your code is producing new values within the loop but doesn't do anything with those values. Moreover, word here is a value and not a reference to your array values, so you can't modify them directly from within your forEach() loop and expect it to modify the string values from your array. You instead need to create a new array, with each element transformed, which can be done by using .map() and returning the new value:
function toCamelCase(str) {
const array = str.split(/[_-]/);
return array.map((word, i) => {
return i === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1)
}).join("");
}
console.log(toCamelCase("this-is-some-text"));
Note that you can remove the capturing group from your .split() to remove the _ and - chars from your array so that you don't need to remove them when you map.
Note that for something like this, if you're already using regular expressions in your .split(), you might consider using .replace() with a replacement function, for example, something like:
function toCamelCase(str) {
return str.replace(/-\w/g, ([,m]) => m.toUpperCase());
}
console.log(toCamelCase("this-is-some-text"));
word == "-" ? word.replace("") : word.charAt(0).toUpperCase() is just a ternary statement floating in space. This code isn't altering any variables. It's equivalent to:
if(word == "-"){
word.replace("")
}
else{
word.charAt(0).toUpperCase()
}
Really, you don't need to mess with arrays if you make use of .replace()'s callback function.
function toCamelCase(str) {
// Match underscore or dash followed by a letter, case-insensitively
// Store the letter in a capture group; $1 in this case
return str.replace( /[_-]([a-z])/gi, function( matches ) {
// Uppercase the letter
return matches[ 1 ].toUpperCase()
} );
}
console.log( toCamelCase( 'to-be_Camel_cased' ) );

a bit clarafication on using spread and string manipulation, foreach loop

so I've wrote this function, i want to uppercase the vowels and lowercase every other letter,
problem the end result ends with the same string, I'm new to spread and for-each,
after i spread a string does it become an array?
when i manipulate letters does it suppose to become a string again with the manipulations or do i need to join it? why aren't the upper and lowercase functions don't work?
the function:
function upperCase(str) {
var vowels = "aeiou";
[...str].forEach(letter => {
if (vowels.includes(letter)) letter.toUpperCase();
letter.toLowerCase();
});
console.log(str);
}
You have several problems:
.toUpperCase and toLowerCase return the new value, they don't mutate the existing value (and strings are immutable anyway)
Even if they did mutate the existing value, they'd change the letter string in the array and not the original string
You didn't use else to toLowerCase always runs
You need to:
return a value
Use map to collect the values
Use join() to turn the array back into a string
Such:
function upperCase(str) {
const vowels = "aeiou";
const result =
[...str]
.map(
letter =>
(vowels.includes(letter))
? letter.toUpperCase()
: letter.toLowerCase()
).join("");
console.log(result);
}
upperCase("The quick brown fox jumps over the lazy dog");
You need to assign the result of your foreach to something.
function upperCase(str) {
var vowels = "aeiou";
[...str].forEach(letter => {
if (vowels.includes(letter)) letter.toUpperCase();
letter.toLowerCase();
});
console.log(str);
}
[...str] is creating an array, looping over it, preforming an action, but then not saving the resulting array to any variable at the end. You're also missing an else and/ or a return. I think a map also makes more sense in this case.
function upperCase(str) {
var vowels = "aeiou";
const result = [...str].map(letter => {
if (vowels.includes(letter)) return letter.toUpperCase();
return letter.toLowerCase();
});
console.log(result);
}
If you just want to manipulate a string you might want to use the replace function
const newString = str.toLowerCase().replace(/[a,e,i,o,u]/g, letter => letter.toUpperCase())
This first puts everything to lower case, and afterwards replaces all vowels (matching the regular expression) by their upper case versions.

Javascript: Map function weird behaviour

I am using the below code to identify if a character is duplicated, if it is then I replace with a specific char, else another char.
This code works
function dup(str) {
return str
.toLowerCase()
.split("")
.map((index, nonsense, s) => {
console.log(s);
return s.indexOf(index) == s.lastIndexOf(index) ? "(" : ")";
})
.join("");
}
But I do not understand why, the variable 'nonsense' makes it work. If you remove that unused var I get errors.
How can an unused var affect how map works?
The problem is with the order of the arguments and the value at specific locations
function dup(str) {
return str
.toLowerCase()
.split("")
.map((char, index, self) => { // the order is char, index and the current array in the 3rd argument
console.log(self);
return self.indexOf(char) == s.lastIndexOf(char) ? "(" : ")";
})
.join("");
}
If you wish to remove the issue with unused variable (for example, say with eslint) use the _ or prefix with _
function dup(str) {
return str
.toLowerCase()
.split("")
.map((char, _, self) => { // the order is char, index and the current array in the 3rd argument
console.log(self);
return self.indexOf(char) == self.lastIndexOf(char) ? "(" : ")";
})
.join("");
}
EDIT
Though unrelated,a more optimal way to do it would be to use Set to deduplicate.
function dup(str) {
return Array.from(new Set(str
.toLowerCase()
.split(""))
.join("");
}
This has less to do with .map() and more to do with receiving arguments.
The function passed to .map is automatically passed 3 arguments (which you are calling index, nonsense, and s here). In JavaScript, you are not required to specifically capture any of them with argument names, but if you want to use the second or third one, you will need to provide some argument name(s) for the ones you are going to skip over to indicate that you are interested in the third argument.
Having said that, the arguments passed to .map() (in order) are: element, index, array and your names suggest that you believe it's: index, element, array. So a better naming convention would be as shown below:
function dup(str) {
return str
.toLowerCase()
.split("")
.map((char, index, ary) => {
console.log(ary);
return ary.indexOf(index) == ary.lastIndexOf(index) ? "(" : ")";
})
.join("");
}
dup("The quick quick brown fox.");
in your code index represent the current char, nonsense represents the indexOf that char at s array. if you remove nonsense index will be represent the char and s will be represent the indexOf that char. that cause the error because you are trying to do s.indexOf(index) while s is of type number
try to do it like this
function dup(str) {
return str
.toLowerCase()
.split('')
.map(s => {
console.log(s)
return str.indexOf(s) == str.lastIndexOf(s) ? '(' : ')'
})
.join('')
}
From the docs:
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
As you can see, the map function takes up to three params, where the second and third are optional. Your variables index, nonsense and s are filling in for the current value, the actual index and the array. Remove nonsense and your s variable becomes the current index of map, instead of your array.
That is the expected behavior.

Is there an elegant way to chain join() after a foreach()?

I am trying to write something like this:
DOMElement
.innerHTML
.toLowerCase()
.split(' ')
.forEach(function(word) {
return word.charAt(0).toUpperCase() + word.slice(1);
})
.join(' ')
Since join needs to receive an array, is there an elegant way to provide it one?
You could replace Array#forEach with Array#map.
The map() method creates a new array with the results of calling a provided function on every element in this array.
.map(function(word) {
return word.charAt(0).toUpperCase() + word.slice(1);
})

Reverse vowels in a string, using regex

I am working on an algorithm that takes in a string for input, and reverses the vowels of the string.
'hello' should return as 'holle'
'wookiE' should return as 'wEikoo'
Could str.replace be used as a solution?
function reverseVowels(str) {
return str.replace(/[aeiou]/-g, /[aeiou]+1/);
}
I am not sure what the second parameter for the replace function would be. I intended to find the first vowel and then move on to the next one to replace it with. Can this be done just with this method or is a forEach/for loop needed?
You could do this in two phases:
extract the vowels into an array
perform the replace on the original string, calling a function on each match and popping the last vowel from the stack to replace it.
Code:
function reverseVowels(str){
var vowels = str.match(/[aeiou]/g);
return str.replace(/[aeiou]/g, () => vowels.pop());
}
// example
var original = 'James Bond';
var result = reverseVowels(original);
// output for snippet
console.log(original + ' => ' + result);

Categories

Resources