Finding both characters and putting them in a new array - javascript

I've created a function that passes in a string and a character. The string is saturday and the character is a.
I want the result to be an array that contains all the index numbers of where the letter 'a' sits in saturday.
Then array ends up with only [1]. So it finds the first a sitting at the second index. I tested this by changing saturday to soturday and the console prints the array with [6].
I want the result to be [1, 6]
I've tried putting the return result outside the next set of {} braces but no joy.
const subLength = (str, cha) => {
let result = [];
for (let i = 0; i < str.length; i++) {
if (str.charAt(i) === cha) {
result.push(str.indexOf(cha));
return result;
}
}
};
console.log(subLength('Saturday', 'a'));

2 small problems with your code
The return statement is in the for loop. The first time the loop hits that your loop will stop and the function will return. This is why you are only getting 1 result. Move the return outside the loop.
Once the above is fixed you will realize that your array will now return [1, 1]. This is because str.indexOf(cha) will always return 1 since it's returning the index of the first a. To fix this, you should be appending the index i to your array instead since it represents the index of the current char.
const subLength = (str, cha) => {
let result = [];
for (let i = 0; i < str.length; i++) {
if (str.charAt(i) === cha) {
result.push(i);
}
}
return result;
};
console.log(subLength('Saturday', 'a'));

You are pretty close.
In your code the return is being executed as soon as a match is found. You want to return after you've checked every char - so I've moved it after the foreach.
indexof has a second parm, which defines the char to start looking from. If you omit it, you will get the index of the first match every time - which is not what you want.
const subLength = (str, cha) => {
let result = [];
for(let i = 0; i < str.length; i++){
if(str[i] === cha) {
result.push(str.indexOf(cha, i));
}
}
return result;
};
console.log(subLength('Saturday', 'a'));
Room for improvement
Since you are iterating over every char anyways, you can simply store every i where str[i] matches cha.
So optimized:
const subLength = (str, cha) => {
let result = [];
for(let i = 0; i < str.length; i++){
if(str[i] === cha) {
result.push(i);
}
}
return result;
};
console.log(subLength('Saturday', 'a'));
An even simpler version using regex:
const subLength = (str, cha) => {
return [...str.matchAll(new RegExp(cha, 'g'))].map(e => e.index);
};
console.log(subLength('Saturday', 'a'));

How about putting the return result; outside of the for loop?

Something like this should work, if it is case-sensitive
const subLength = (str, cha) => {
const chaArr = str.split('');
const result = [];
chaArr.forEach((v, i) => {
if (v === cha) result.push(i);
})
return result
};
console.log(subLength('Saturday', 'a'));

Related

How to remove only one of repeated chars in string using JavaScript

I have a string with repeated chars like : 'CANADA'.
And I am trying to get the string which removed only one of repeated chars :
'CNADA', 'CANDA', 'CANAD'.
I've tried it with subString, but it returned the part of string removed.
Also I've tried it with reduce, but it ended up removing all the repeated chars ('CND').
What is the way of removing only one char at time?
The results can be stored in array. (results = ['CNADA', 'CANDA', 'CANAD'])
Thank you.
You can achieve this by utilizing the second parameter of String#indexOf() which specifies the position from which to start the search. Here in a while loop, and using a Set to remove dulplicates before returning.
function getReplaceOptions(str, char) {
let res = [], i = str.indexOf(char, 0);
while (i !== -1) {
res.push(str.substring(0, i) + str.substring(++i));
i = str.indexOf(char, i)
}
return Array.from(new Set(res))
}
console.log(getReplaceOptions('CANADA', 'A'));
console.log(getReplaceOptions('Mississippi', 's'));
You can first count all the occurrences in the string. Later you can iterate over the script and if the count is greater than 1 you can remove that character.
const theString = 'CANADA'
const letterCount = {}
const resultArr = []
for (var i = 0; i < theString.length; i++) {
const theLetter = theString.charAt(i)
if(letterCount[theLetter]){
letterCount[theLetter] = letterCount[theLetter] + 1
}
else{
letterCount[theLetter] = 1
}
}
console.log(letterCount)
for (var i = 0; i < theString.length; i++) {
const theLetter = theString.charAt(i)
if(letterCount[theLetter] && letterCount[theLetter] > 1){
resultArr.push(theString.substr(0, i) + theString.substr(i + 1))
}
}
console.log(resultArr)
If you want to remove only the first repeating character then you can use matchAll here as:
Just see the browser compatibility before using this
const str = 'CANADA';
const firstRepeatedChar = 'A';
const result = [];
for (let { index } of str.matchAll(firstRepeatedChar)) {
result.push(str.slice(0, index) + str.slice(index + 1));
}
console.log(result);
NOTE: If you want to search for the first repeating character then remove it, then you can do as:
const str = 'CANADA';
let firstRepeatedChar = '';
const set = new Set();
for (let i = 0; i < str.length; ++i) {
if (!set.has(str[i])) {
set.add(str[i]);
} else {
firstRepeatedChar = str[i];
break;
}
}
const result = [];
for (let { index } of str.matchAll(firstRepeatedChar)) {
result.push(str.slice(0, index) + str.slice(index + 1));
}
console.log(result);
You could use some Array magic to remove duplicate characters:
function removeDuplicateCharacters(value) {
// convert string to array and loop through each character
return String(value).split('').filter(function(char, index, all) {
// return false if char found at a different index
return (index === all.indexOf(char));
})
.join(''); // convert back to a string
}
// returns `CAND`
removeDuplicateCharacters('CANADA');
// returns `helo wrd`
removeDuplicateCharacters('hello world');

Finding first occurrence of each digit in an array

Taking each four digit number of an array in turn, return the number that you are on when all of the digits 0-9 have been discovered. If not all of the digits can be found, return "Missing digits!"
I've tried to loop through then set a conditional if (i != i+1) push into new array this just gave me the array, it's apparent my logic is wrong. could anyone help me out
For example calling this function with
arr = findAllDigits([5175, 4538, 2926, 5057, 6401, 4376, 2280, 6137, 8798, 9083])
the code should return 5057.
While calling
arr = findAllDigits([4883, 3876, 7769, 9846, 9546, 9634, 9696, 2832, 6822, 6868])
should return "missing numbers"
function findAllDigits(arr) {
newArr = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] != arr[i + 1]) newArr.push(arr[i]);
console.log(newArr);
}
}
Do I need to split because it is taking everything before the comma as
one number, then iterate over?
You can use Set here
Loop over the array and then create a set, You have to return the current number if set size becomes 10 because you need to check 0-9
function findAllDigits(arr) {
const set = new Set();
for (let n of arr) {
String(n)
.split("")
.forEach((c) => set.add(c));
if (set.size === 10) return n;
}
return "Missing digits!";
}
const arr1 = [5175, 4538, 2926, 5057, 6401, 4376, 2280, 6137, 8798, 9083];
const arr2 = [4883, 3876, 7769, 9846, 9546, 9634, 9696, 2832, 6822, 6868];
console.log(findAllDigits(arr1));
console.log(findAllDigits(arr2));
Your for loop is only checking to see if the array entry is equal to the next one. You need to split up the digits inside each entry and store them individually:
function findAllDigits(arr) {
newArr = [];
for (let i = 0; i < arr.length; i++) {
// now iterate the individual digits
const entryAsString = arr[i].toString();
for (let j = 0; j < entryAsString.length; j++) {
// if we haven't seen the digit before, add it to the array
if(!newArr.includes(j) {
newArr.push(j);
}
}
// we know we have all digits when newArr is 10 entries long
if (newArr.length) {
console.log(arr[i]);
// you can also return this value here
}
}
}
One more solution:
const arr1 = [5175, 4538, 2926, 5057, 6401, 4376, 2280, 6137, 8798, 9083];
const arr2 = [4883, 3876, 7769, 9846, 9546, 9634, 9696, 2832, 6822, 6868];
const findAllDigits = (arr) => {
// Declare new Set: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
const digits = new Set();
// return the first item from array that fits the condition,
// find() method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
return arr.find((curr) => (
// String(5175) -> '5175' : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
// [...'5175'] -> ['5','1','7','5'] : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
// .forEach(digits.add, digits) - forEach with callback function and context : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
// comma operator lets get rid of return : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator
[...String(curr)].forEach(digits.add, digits),
// condition - is find() method need to return an item
(digits.size === 10)
// if returned value is not undefined or null return finded number oterwise error string
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
)) ?? "Missing digits!";
};
console.log(findAllDigits(arr1)); //5057
console.log(findAllDigits(arr2)); //Missing digits!

Find Missing Character in a Character Array (javascript)

I am trying to write a function that takes in an array of individual characters (eg.['a','b','d']) and returns the first character that is missing (eg. 'c'). I am not sure why my current function doesn't work as described.
const alph = "abcdefghijklmnopqrstuvwxyz";
const findMissingLetter = (arr) => {
arr.forEach((l, i, a) => {
const ltrIdx = alph.indexOf(l); //a's index in the alph is 0
const arrNxtLtr = a[i+1]; //the next ltr after a is c
if(arrNxtLtr !== alph[ltrIdx + 1]) return alph[ltrIdx + 1] //return the letter that is missing from the arr
})
return -1 //return -1 if there is no missing char
}
console.log(findMissingLetter(['a','c']))
ps. I've seen similar approaches to solve this general problem, I am just simply wondering what I've done wrong with my function so I can learn.
Thank you!
If you simply want to find the first mismatch between two strings, then just compare them character by character until you find a mismatch or reach the end of the input string:
const alph = "abcdefghijklmnopqrstuvwxyz";
const findMissingLetter = (arr) => {
for(let i=0; i<arr.length; i++) {
if(arr[i] !== alph[i]) {
return alph[i]; // found the first mismatch
}
}
return -1 // return -1 if there is no missing char
}
console.log(findMissingLetter([]),"-1?");
console.log(findMissingLetter(['a']),"-1?");
console.log(findMissingLetter(['b']),"a?");
console.log(findMissingLetter(['a','b']),"-1?");
console.log(findMissingLetter(['a','c']),"b?");
And avoid forEach() if you want to return from inside a loop as it was commented already.
And if the input string does not have to start at the beginning of the "big" string, locate it's first character and do the comparison from there:
const alph = "abcdefghijklmnopqrstuvwxyz";
const findMissingLetter = (arr) => {
if(arr.length===0)
return -1;
let start = alph.indexOf(arr[0]);
for(let i=0; i<arr.length; i++) {
if(arr[i] !== alph[start+i]) {
return alph[start+i]; // found the first mismatch
}
}
return -1 // return -1 if there is no missing char
}
console.log(findMissingLetter([]),"-1?");
console.log(findMissingLetter(['a']),"-1?");
console.log(findMissingLetter(['b']),"-1?");
console.log(findMissingLetter(['a','b']),"-1?");
console.log(findMissingLetter(['a','c']),"b?");
console.log(findMissingLetter(['b','c','e','f']),"d?");
The reason is that forEach ignores return or any shortcircuit statement. You must instead of trying return the value from the foreach, just save it into another variable and return that variable after the forEach is done.
const alph = "abcdefghijklmnopqrstuvwxyz";
const findMissingLetter = (arr) => {
let missingLetter
arr.forEach((letter, index) => {
if(letter !== alph[index]) missingLetter ??= alph[index]
else missingLetter = -1
})
return missingLetter
}
console.log(findMissingLetter(['a','c']))

How to find the longest common prefix in an array of strings?

I'm trying to solve this using the .every method but it's not returning true and therefore it's not adding onto my string and I'm not sure why.
var longestCommonPrefix = function(arr) {
if (arr.length === 0) {
return undefined;
}
let result = '';
for (let i = 0; i < arr.length; i++) {
if (arr.every(x => arr[i].charAt(i) === x)) {
result += arr[i].charAt(i);
}
}
return result
}
console.log(longestCommonPrefix(["flower", "flow", "flight"])); //fl
You need to iterate over one string, not over the whole array: check if the first character of the string is present everywhere, then the second character, etc:
var longestCommonPrefix = function(arr) {
if (arr.length === 0) {
return undefined;
}
let result = '';
for (let i = 0; i < arr[0].length; i++) {
if (arr.every(x => x.charAt(i) === arr[0][i])) {
result += arr[i].charAt(i);
} else break;
}
return result;
}
console.log(longestCommonPrefix(["flower", "flow", "flight"])); //fl
Your use of Array.every is along the right lines. You want to check that every string in the array has the same character at position i. I think you got confused when you named the parameter x, when it is in fact a string :)
var longestCommonPrefix = function(words) {
if (words.length === 0) {
return "";
}
const letters = [];
const lengthOfShortestWord = Math.min(...words.map(word => word.length));
for (let i = 0; i < lengthOfShortestWord; i++) {
const char = words[0][i];
if (words.every(word => word[i] === char)) {
letters.push(char);
} else {
break;
}
}
return letters.join("");
}
console.log(longestCommonPrefix(["flower", "flow", "flight"])); //fl
Unless I am mistaken the longest prefix is never going to be greater than the smallest string in the array.
In this case "fl" is both the smallest string and the longest common prefix:
["flower", "fl", "flight"]
So start with finding the smallest string in arr:
let [sm] = [...arr].sort((a, b) => a.length - b.length);
Then check that all strings in arr start with sm:
arr.every(str => str.startsWith(sm));
If that isn't the case then shorten sm by one character:
sm = sm.slice(0, -1);
And keep going until you eventually find the longest prefix or sm becomes an empty string:
const prefix = arr => {
let [sm] = [...arr].sort((a, b) => a.length - b.length);
while (sm && !arr.every(str => str.startsWith(sm))) sm = sm.slice(0, -1);
return sm;
};

Running into error creating a Javascript function

I am trying to write a function to change a string written in Snake Case to Camel Case, but running into an error.
function snakeToCamel(string) {
arr = [...string];
for (i of arr) {
if (i === "_") {
let upperCaseLetter = arr[i+1].toUpperCase();
arr.splice(i+1,1,upperCaseLetter);
arr.splice(i,1)
}
};
return arr;
}
The error is here. I can't find what is wrong in the line stated in the error. What is going on?
snakeToCamel("you_dont_know")
snake-to-camel.js:5 Uncaught TypeError: Cannot read property 'toUpperCase' of undefined
at snakeToCamel (snake-to-camel.js:5)
at <anonymous>:1:1
In a for-of loop, the control variable is the array element, not an index. So i in your example is a string. So arr[i+1].toUpperCase(); will do string concatenation and try to look up a property with a name like s1, not 1.
If you want to use the index, you want a for loop or a forEach call (or even map, since that's kind of what you're doing), not a for-of loop.
A couple of other notes:
You need to be sure to declare your variables; right now, your code is falling prey to what I call The Horror of Implicit Globals, creating a global called arr. Add const or let before arr.
You don't put ; after blocks attached to control-flow statements. (You can have them there, because empty statements are allowed, but they're not supposed to be there.)
For example, using a for loop:
function snakeToCamel(string) {
// `const` because we never reassign `arr`
const arr = [...string];
// Traditional `for` so we have the index
for (let i = 0, len = arr.length; i < len; ++i) {
const ch = arr[i];
if (ch === "_") {
if (i === len - 1) {
// Trailing _, just remove it
arr.splice(i, 1);
--i;
--len;
} else {
let upperCaseLetter = arr[i + 1].toUpperCase();
// You can remove the _ and the lowr case letter
// in a single `splice` rather than multiple ones
arr.splice(i, 2, upperCaseLetter);
--i; // Need to do this to allow for multiple `_` in a row
--len;
}
}
};
return arr;
}
console.log(snakeToCamel("one_two__three_"));
Or using map:
function snakeToCamel(string) {
let lastWasUnderscore = false;
const result = [...string]
.map(ch => {
const thisIsUnderscore = ch === "_";
if (lastWasUnderscore && !thisIsUnderscore) {
lastWasUnderscore = false;
return ch.toUpperCase(); // or `.toLocaleUpperCase()`
}
lastWasUnderscore = thisIsUnderscore;
return thisIsUnderscore ? null : ch;
})
.filter(ch => ch !== null);
return result;
}
console.log(snakeToCamel("one_two__three_"));
You were actually fairly close to the solution!
Instead of using a for-of loop I would suggest you use a normal for loop.
This way you can access the index i
function snakeToCamel(string) {
const arr = [...string];
for (let i = 0; i < arr.length; i++) {
if (arr[i] === "_") {
let upperCaseLetter = arr[i+1].toUpperCase();
arr.splice(i+1,1,upperCaseLetter);
arr.splice(i,1)
}
}
return arr.join("");
}
Here's the code I wrote. (needs to be refined for DRY principle)
function STC(string) {
const arr = [...string];
let output = '';
for (const letter of arr) {
if (letter == '_') {
output += arr[arr.indexOf(letter)+1].toUpperCase()
arr.splice(arr.indexOf(letter), 1)
} else {
output += letter;
}
}; return output;
}
I just add to the string instead of an array. I also delete the underscore. Tell me if it works.
function snakeToCamel(string) {
const arr = [...string];
arr.forEach((v, i) => {
if (v === "_") {
arr.splice(i+1,1, arr[i+1].toUpperCase());
arr.splice(i,1)
}
});
return arr.join("");
}
const result = snakeToCamel('a_b_c');
console.log(result);

Categories

Resources