Related
I see this similar algorithm was posted on stackoverflow, nevertheless I cannot understand, so I decided to post once more.
function capitalizeFirst(arr) {
if (arr.length === 1) {
return [arr[0].toUpperCase()]
}
let res = capitalizeFirst(arr.slice(0, -1))
res.push(arr.slice(arr.length - 1)[0].toUpperCase())
return res
}
console.log(capitalizeFirst(['dog', 'car', 'horse']))
Things I do not understand...
Why it is inside square brackets return [arr[0].toUpperCase()]
why not just return arr[0].toUpperCase()
Why "arr" is getting sliced twice:
here
let res = capitalizeWords(arr.slice(0,-1)
and here
res.push(arr.slice(arr.length-1)[0].toUpperCase())
Overall, I am lost, please help
I see that the OP wants to explain some found code. First, it's not very good code. The function can be restated in a couple easy to read lines.
Here's the not-so-good code annotated (comments *in stars* answer the specific OP questions)
function capitalizeWords(arr) {
// this is the degenerate case: a single item array
if (arr.length === 1) {
return [arr[0].toUpperCase()] // return a *single item array* with the one element capitalized
// incidentally, toUpperCase capitalizes all letters, not only the first, as stated in the OP title
}
// here, length must be zero or > 1. If zero, the remaining code will fail, indexing past 0
// otherwise, if length > 1, this code will run the function on the array minus
// the last element it will return an array (see above) for that last element
let res = capitalizeWords(arr.slice(0, -1))
// this says capitalize the last element.
// it's super clumsy, grabbing the last element by *slicing the array again* just before the end,
// getting that one element from the slice, and using with toUpperCase
// then pushing that uppercase result onto the result array
res.push(arr.slice(arr.length - 1)[0].toUpperCase())
return res
}
Here's a cleanup. First, isolate the capitalization logic and get that tested and correct. It will look like this:
const capitalizeWord = word => word[0].toUpperCase() + word.slice(1);
Next, realize that the most degenerate (elemental) case is capitalizing an empty array. The result of capitalizing an empty array is an empty array.
// something like
return !arr.length ? [] : // ... recursion will go here
When recursing with arrays, we generally say: "do something with the first element, and do the function with the rest of the elements". In JS, it's much more elegant to refer to the "first and rest" than to "all but the last and the last".
// first element (after we've established > 0 length)
arr[0]
// the rest of the elements
arr.slice(1)
Putting this all together...
const capitalizeWord = word => word[0].toUpperCase() + word.slice(1);
function capitalizeWords(arr) {
return arr.length ? [ capitalizeWord(arr[0]), ...capitalizeWords(arr.slice(1))] : [];
}
console.log(capitalizeWords(['dog', 'car', 'horse']))
I would forget about what that code does and concentrate on the steps you need to take to make your function work.
Recursive - so the function needs to call itself but you need to find a way to identify which element you're working on.
You need a way to break out of the recursion when you reach the end of the array.
You need a way to separate out the first letter of an element from all the rest, and update the element with a transformed string.
Here's how I might approach it.
// Pass in the array, and initialise an index
// variable
function capitalizeFirst(arr, index = 0) {
if (!arr.length) return 'Empty array';
// If we're at the end of the array
// return the array
if (index === arr.length) return arr;
// If the element is not empty
if (arr[index].length) {
// Get the first letter, and place all
// the other letters in an array called `rest`
// You can use destructuring here because strings
// are iterable
const [first, ...rest] = arr[index];
// Update the element at the current index
// with the new string making sure you join up `rest`
arr[index] = `${first.toUpperCase()}${rest.join('')}`;
}
// Call the function again increasing the index
return capitalizeFirst(arr, ++index);
}
console.log(capitalizeFirst(['dog', 'car', 'horse']));
console.log(capitalizeFirst([]));
console.log(capitalizeFirst(['dog', '', 'horse']));
console.log(capitalizeFirst(['dog', 'o', 'horse']));
Additional documentation
Destructuring assignment
Rest parameters
Template/string literals
your confusion code
1.let res = capitalizeWords(arr.slice(0,-1)
2.res.push(arr.slice(arr.length-1)[0].toUpperCase())
1.res is an variable array . when this line of code will run let res = capitalizeWords(arr.slice(0,-1)) that means first thing will be done is from your array ['dog', 'car', 'horse'] it will take out the first item that is "dog" and after capitalizeWords function will run and inside capitalizeWords function the argument passed from res is "dog" . and when the function will run if block will run because now arr has one element that is ["dog"] and that will be converted to ["DOG"] . and as like this ['car', 'horse'] this 2 elements will be converted to capital .
but it is a bit complex code to understand as a beginner.
so,you can use my simplify code . i hope you can understand this easily !!
function capitalizeWords(arr) {
if(arr.length === 1) {
return [arr[0].toUpperCase()]
}
let res = []
for (let i of arr){
res.push(i.toUpperCase())
}
return res
}
console.log(capitalizeWords(['dog', 'car', 'horse']))
your another confusion is
return [arr[0].toUpperCase()]
if you write return arr[0].toUpperCase() that means arr[0]="dog" (its a string not an array) . if you just want to print it as a string then you can write arr[0].toUpperCase() :"dog" but if you want to console it as an array then you have to write this : [arr[0].toUpperCase()] :["dog"]
Update
Added some input checking:
if (array.length < 1) return `ERROR Empty Array`;
// Return error message if input is an empty array
if (typeof str === "string" && /[a-z]/.test(str.charAt(0))) {...
/**
* Ignore all non-string data and any string that doesn't start with
* a lower case letter
*/
The code in OP doesn't capitalize each word in an array, it capitalizes every letter of each word. I honestly didn't really try to figure out what's exactly wrong because there's no recursion in the OP anyhow.
Recursion
A function that calls itself within the function (which is itself).
A base condition must be met in order for the function to call itself.
The parameters should change upon each recurse.
The function will cease calling itself once the base condition is no longer true.
In the OP, there's no base condition (see Recursion 2).
In the following example is a recursive function that capitalizes each word of an array.
Pass in the array and index (if index is undefined it defaults to 0)
function capWords(array, index = 0) {...
// array = ["dog", "cat', 'bird'], index = 0
Find the word from the array at the index
let str = array[index];
// str = 'dog'
Get the first letter of that word and capitalize it
let cap = str.charAt(0).toUpperCase();
// cap = "D"
Then concatenate cap to the rest of that word and then reassign the new word to the array at index
array[index] = cap + str.slice(1);
// array = ['Dog', 'cat', 'bird']
If index is less than the length of the array -1...
if (index < array.length - 1) {...
/**
* See Recursion 2
* index = 0, array.length -1 = 2
*/
...return and call capWords(array, index + 1)...
return capWords(array, index + 1)
/**
* See Recursion 1
* array = ['Dog', 'cat', 'bird'], index = 1
* See Recursion 3
*/
...otherwise return array
return array
/**
* See Recursion 4
* After calling capWords() recursively 2 more times, the array is
* returned one more time
* array = ["Dog", "Cat", "Bird"]
*/
function capWords(array, index = 0) {
if (array.length < 1) return `ERROR Empty Array`;
let str = array[index];
if (typeof str === "string" && /[a-z]/.test(str.charAt(0))) {
let cap = str.charAt(0).toUpperCase();
array[index] = cap + str.slice(1);
}
if (index < array.length - 1) {
return capWords(array, index + 1);
}
return array;
}
console.log(capWords(['dog', 'cat', 'bird'], 0));
console.log(capWords(['dog', '', 'bird']));
console.log(capWords([2, 'cat', 'bird'], 0));
console.log(capWords(['dog', 'cat', {}], 0));
console.log(capWords([]));
You just forgot to select the First letter charAt(0) and to add more logic to connect the first letter with the other part of the word array[0].charAt(0).toUpperCase() + array[0].slice(1).toLowerCase();
The same situation when you are recursively pushing every word into an array.
function capitalizeFirst (array){
if (array.length === 1) {
return [array[0].charAt(0).toUpperCase() + array[0].slice(1).toLowerCase()];
}
var word = capitalizeFirst(array.slice(0, -1));
word.push(array.slice(array.length-1)[0].charAt(0).toUpperCase() +
array.slice(array.length-1)[0].slice(1).toLowerCase());
return word;
}
Consider this:
var longestCommonPrefix = function(strs) {
strs.forEach((item, index) => {
let splitArr = item.split('');
console.log('split array item is: ' + splitArr)
});
};
longestCommonPrefix(["flower","flow","flight"])
https://leetcode.com/problems/longest-common-prefix/
I need to compare these arrays to find the common prefix in them. So the output of this code at the ends needs to be:
common prefix is: "fl"
As of right now the output of the above code block is this
split array item is: f,l,o,w,e,r
split array item is: f,l,o,w
split array item is: f,l,i,g,h,t
I need to either
Loop by each character and array so the output is something like:
f,f,f,l,l,l,o,o,i,w,w,g,e,,h,r,,t
I tried to do this like this:
Looping Through an Array of Characters
You might want to take a look at the String's split method.
So I am already doing that, and my thought process is now this:
lets get our arrays, iterate over each character, and then make a new master array where we can count each instance of a letter appearing 3 times and print out that character, in order to get our common prefix.
So now that approach is this:
var longestCommonPrefix = function(strs) {
// establish the new array
// we need this for later, outside our loop so we can have a giant array to sort/look at/count
let charArray = [];
// loop through each array
strs.forEach((item, index) => {
// split the array by character
let splitArr = item.split('');
// test console log
console.log('split array item is: ' + splitArr)
// iterate over each character, and push it into a new array
splitArr.forEach((letter, index) => {
charArray.push(letter)
});
});
// log final array
console.log('FINAL ARRAY IS...: ' + charArray)
};
longestCommonPrefix(["flower","flow","flight"])
So we're getting closer because we're now here:
FINAL ARRAY IS...: f,l,o,w,e,r,f,l,o,w,f,l,i,g,h,t
But we're not quite there with what we want, f,f,f,l,l,l,o,o,i,w,w,g,e,,h,r,,t
We need to somehow sort the array by matching character, I think...?
When we do charArray.sort() we get this:
"FINAL ARRAY IS...: e,f,f,f,g,h,i,l,l,l,o,o,r,t,w,w"
Not quite...
Here are some SO answers based on my google search keyword "sort array by matching characters" that kind of talk about it but aren't quite relevant to my question
Javascript sort an array by matching to string
Sort an array of strings based on a character in the string
What keyword/search should I have used to find the results?
How can I sort this array from e,f,f,f,g,h,i,l,l,l,o,o,r,t,w,w to f,f,f,l,l,l,o,o,i,w,w,g,e,,h,r,,t ... ?
Here's a possible solution, needs to cover cases with an empty array but you get an idea.
While all letters at index c are the same I keep looping, otherwise I exit.
At the end I take c characters from the first word as it's the length of the common prefix.
function longestCommonPrefix(strs) {
var splits = strs.map((item) => item.split(''));
var c = 0;
var matches = true;
while (matches) {
var letter = splits[0][c];
if (letter != null) {
matches = splits.every(s => s[c] == letter);
if (matches)
c++;
} else matches = false;
}
var prefix = strs[0].slice(0, c);
console.log("The prefix is: " + prefix);
};
longestCommonPrefix(["flower", "flow", "flight"])
javascript function which returns an array of string in such a way that it contains all possible upper-case letters of the input string one at a time sequentially.
uppercase("hello") ➞ ["Hello", "hEllo", "heLlo", "helLo", "hellO"]
what i have tried is
const helloCapital = (str) => {
let a = [];
for (let i in str) {
a.push(str[i].toUpperCase() + str.slice(1));
}
return a;
};
but it gives weird results
[ 'Hello', 'Eello', 'Lello', 'Lello', 'Oello' ]
This looks like a challenge for a course or challenges website.
If that is the case, it is really, really not cool to come here and ask for that answer.
But, since I'm already here, here it goes a working solution.
const capitals = s => Array.from(s,(_,i)=>s.slice(0,i)+_.toUpperCase()+s.slice(i+1))
UPDATE: Explaining the code
Array.from works on iterable objects, such as strings, Arrays and, ArrayLike objects for example.
It calls the function you pass as the first argument on each element of the iterable, in this case, the string.
The function receives 1 element of the iterable (the _) and the position of that element (the i)
So the function is returning a concatenation of 3 things:
* the substring of the original string from 0 to i
* the current element of the iterable, or current character, toUpperCase()
* the substring of the original string from i+1 to the end of the string.
Your logic is wrong, to work you need to concat the slice before letter with capitalized letter and with the slice after letter.
function capitalizeEachLetter (text) {
return Array.from(text, (letter, index) =>
text.slice(0, index) + letter.toUpperCase() + text.slice(index + 1)
);
}
use array array map,
var str = "hello";
var capitals = Array.from(str).map((e, i, ar) => {
let r = [...ar];
r[i] = ar[i].toUpperCase();
return r.join('');
});
console.log(capitals)
I want to check if string one in array contain the letters from words in string 2. Here's my example array:
(["Floor", "far"]);
function should return false because "a" is not in string "Floor"
But for array like this:
(["Newbie", "web"]);
It should return true because all of letters from "web" are in "Newbie".
Here's my code so far...
function mutation(arr) {
var newArr = [];
for (i=0; i<arr.length; i++) {
newArr.push(arr[i].toLowerCase().split(""));
}
for (i=0; i<newArr.length; i++) {
for (j=0; j<newArr[i].length; j++) {
console.log(newArr[0][j]+ (newArr[1][j]));
}
}
}
mutation(["Newbie", "web"]);
I know that it won't work and I'm out of ideas how to make it. I try to make a set of all letters in two array and compare them. If there is at least one false the function should return false. Should I nest indexOf() method somewhere?
I think this should work for you. Break up the string of letters to check for into an array. Iterate over the array getting each letter and checking if the string passed in contains the letter, setting our result to false if it doesn't.
function mutation(arr) {
var charArr = arr[1].toLowerCase().split("");
var result = true;
charArr.forEach(element => {
if (!arr[0].toLowerCase().includes(element)) {
result = false;
}
});
return result;
}
console.log(mutation(["Newbie", "web"]));
The cool way would be:
const mutation =([one, two]) => (set => [...two.toLowerCase()].every(char => set.has(char)))(new Set(one.toLowerCase()));
How it works:
At first we destructure the passed array into the first and the second word:
[one, two]
Now that we got both, we build up a Set of characters from the first word:
(set => /*...*/)(new Set(one))
All that in an IIFE cause we need the set here:
[...two].every(char => set.has(char))
That spreads the second word in an array, so we got an array of chars and then checks if all characters are part of the set we built up from the other word.
If you want to be sure that one word, which might have several repeating letters, is contained in another, use Array.reduce() to count the letters, and store create a map of letter -> counts. Do that for both words. Check if all entries of 2nd word are contained in the 1st word map using Array.every():
const countLetters = (w) =>
w.toLowerCase()
.split('')
.reduce((r, l) => r.set(l, (r.get(l) || 0) + 1), new Map());
const mutation = ([a, b]) => {
const al = countLetters(a);
const bl = countLetters(b);
return [...bl].every(([k, v]) => v <= (al.get(k) || 0));
};
console.log(mutation(["Floor", "far"])); // false
console.log(mutation(["Floor", "for"])); // true
console.log(mutation(["Floor", "foroo"])); // false
console.log(mutation(["Newbie", "web"])); // true
I have two strings:
var a = 'ABCD';
var b = 'DEFG';
I need to compare these variables to check if there is not a common CHARACTER in the two strings.
So for this case return false (or do something...) because D is a common character in them.
You could merge the two strings then sort it then loop through it and if you find a match you could then exit out the loop.
I found this suggestion on a different stack overflow conversation:
var str="paraven4sr";
var hasDuplicates = (/([a-zA-Z]).*?\1/).test(str)
So if you merge the strings together, you can do the above to use a regexp, instead of looping.
Thank you every one. I tried your solutions, and finally got this :
Merging my two strings into one
to Lower Case,
Sort,
and Join,
using Regex Match if the Final Concatenated string contains any
repetitions,
Return 0 if no Repeat occur or count of repeats.
var a; var b;
var concatStr=a+b;
checkReptCharc=checkRepeatChrcInString(concatStr);
function checkRepeatChrcInString(str){
console.log('Concatenated String rec:' + str);
try{ return
str.toLowerCase().split("").sort().join("").match(/(.)\1+/g).length; }
catch(e){ return 0; }
}
I was also searching for solution to this problem, but came up with this:
a.split('').filter(a_ => b.includes(a_)).length === 0
Split a into array of chars, then use filter to check whether each char in a occurs in b. This will return new array with all the matching letters. If length is zero, no matching chars.
add toUpperCase() to a & b if necessary
So if it only duplicate strings in separate string arrays using .split(''), then I would sort the two string separately, and then do a binary search, start with the array of the shortest length, if the same length the just use the first one, and go character by character and search to see if it is in the other string.
This is obviously too late to matter to the original poster, but anyone else who finds this answer might find this useful.
var a = 'ABCD';
var b = 'DEFG';
function doesNotHaveCommonLetter(string1, string2) {
// split string2 into an array
let arr2 = string2.split("");
// Split string1 into an array and loop through it for each letter.
// .every loops through an array and if any of the callbacks return a falsy value,
// the whole statement will end early and return false too.
return string1.split("").every((letter) => {
// If the second array contains the current letter, return false
if (arr2.includes(letter)) return false;
else {
// If we don't return true, the function will return undefined, which is falsy
return true;
}
})
}
doesNotHaveCommonLetter(a,b) // Returns false
doesNotHaveCommonLetter("abc", "xyz") // Returns true
const _str1 = 'ABCD';
const _str2 = 'DEFG';
function sameLetters(str1, str2) {
if(str1.length !== str2.length) return false;
const obj1 = {}
const obj2 = {}
for(const letter of str1) {
obj1[letter] = (obj1[letter] || 1) + 1
}
for(const letter of str2) {
obj2[letter] = (obj2[letter] || 1) + 1
}
for(const key in obj1) {
if(!obj2.hasOwnProperty(key)) return false
if(obj1[key] !== obj2[key]) return false
}
return true
}
sameLetters(_str1, _str2)