This question already has answers here:
Remove consecutive duplicate characters in a string javascript
(5 answers)
Closed 1 year ago.
I have seen a few examples of this, but they're either not in JS or are terribly inefficient (like the solution I have now). Basically what I want done is a function that takes in a string and removes any characters that are adjacent and the same. As an example, "jjjavvvaaassscript" would become "javascript". What I'm not looking for is where it would become "javscript" (eliminating the second "a"). I do have a working function shown below, but it's absolutely horrendous and I'm looking for a better way to do it.
function removeChar(text, index) {
return(text.slice(0,index)+text.slice(index+1));
}
function removeDuplicates(text) {
var prevChar = "";
var finalT = text;
var i = 0;
for(i = 0; i < text.length; i++) {
if(finalT.charAt(i) == prevChar) {
if(i > finalT.length) {
return finalT;
} else {
finalT = removeChar(finalT, i);
i--;
}
} else {
prevChar = finalT.charAt(i);
}
}
return finalT;
}
Any help would be greatly appreciated!
I'd use a regular expression to match a character, then backreference it as many times as possible (so, for example, it'll match jjj, or a, or vvv, etc), and then replace with the one character:
const removeDuplicates = str => str.replace(/(.)\1*/g, '$1');
console.log(removeDuplicates('jjjavvvaaassscript'));
If you had to iterate more manually, similar to your current method, then:
const removeDuplicates = str => {
let lastChar = str[0];
let finalT = str[0];
for (const char of str.slice(1)) {
if (lastChar !== char) finalT += char;
lastChar = char;
}
return finalT;
};
console.log(removeDuplicates('jjjavvvaaassscript'));
Related
Encoding Input Data: ABC - Output: ZBYX
The encoding happens such that the odd numbered letters of the English alphabet are replaced by their alphabetic opposite, even numbered letters are replaced by a combination of that same letter and it's alphabetic opposite (ie. as shown above 'B' is even numbered alphabet so it got replaced as 'BY', A is replaced by Z, C is replaced by X)
I need to decode the encoded output data to get the input (the reverse logic). I wrote the below function but it doesn't quite give me the expected output for all test cases. (eg: When the input is ZBYX, output comes up correctly as ABC, but in other cases such as:
JQPLO (input) - output comes as QJKL (supposed to come as JKL)
NMLPK (input) - output comes as MNOP (supposed to come as NOP)
)
How should I refactor the below code so that I get the expected output for all test cases?
let alpha="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
function decode(str){
let answer=""
for(let i=0;i<str.length;i++){
if(alpha.indexOf(answer[answer.length-1])%2==0){
if((alpha.indexOf(str[i])+1)%2==0){
continue
}
answer+=alpha[alpha.length-(alpha.indexOf(str[i])+1)]
}else{
answer+=alpha[alpha.length-(alpha.indexOf(str[i])+1)]
}
}
return answer
}
The trick for decoding is, if you get to an even letter l AND the next letter is the opposite of l, then you add l to the decoded output and skip the next letter. Otherwise, you need to just add the opposite of l to the output.
I would recommend trying it yourself before reading the code below, but the below code passed all the test cases you provided.
let alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
function isEven(c) {
return (alpha.indexOf(c) + 1) % 2 === 0;
}
function opposite(c) {
return alpha[alpha.length - alpha.indexOf(c) - 1];
}
function encode(str) {
let answer = "";
for (let i = 0; i < str.length; i++) {
if (!isEven(str[i])) {
answer += opposite(str[i]);
} else {
answer += str[i];
answer += opposite(str[i]);
}
}
return answer;
}
function decode(str) {
let answer = "";
for (let i = 0; i < str.length; i++) {
if (isEven(str[i]) && str[i + 1] === opposite(str[i])) {
answer += str[i];
i++;
} else {
answer += opposite(str[i]);
}
}
return answer;
}
console.log(encode('ABC'));
console.log(decode('ZBYX'));
console.log(decode('NMLPK'));
console.log(decode('JQPLO'));
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const decode = str => {
str = str.split("").reduce((p, c, i, arr) => {
if (alphabet.indexOf(arr[i + 1]) % 2 !== 0)
p += alphabet[25 - alphabet.indexOf(c)];
return p
}, "");
return str;
}
console.log(decode("ZBYX"));
console.log(decode("JQPLO"));
console.log(decode("NMLPK"));
const encode = str => {
str = str.split("").reduce((p, c) => {
if (alphabet.indexOf(c) % 2 !== 0)
p += c + alphabet[25 - alphabet.indexOf(c)];
else
p += alphabet[25 - alphabet.indexOf(c)];
return p
}, "");
return str
}
console.log(encode("ABC"));
I eventually figured out a solution based off my initial program in the question, I just don't know how it works but it passed all test cases; Thanks for all the other answers here, appreciate the effort guys!
here's my updated code:
function decode(str){
try{
let answer=""
if(!(/^[A-Z]+$/).test(str)){
throw Error("Input must only contain upper case letters")
}
for(let i=0;i<str.length;i++){
if(alpha.indexOf(answer[answer.length-1])%2==0){
if((alpha.indexOf(str[i])+1)%2==0){
continue
}
}else{
if(str.length>4)answer=answer.slice(-1)
}
answer+=alpha[alpha.length-(alpha.indexOf(str[i])+1)]
}
return answer
} catch (err){
console.log(err)
}
}
I just added a condition to check for the string length given at the input under the else block, but I guess the other answers here were more logical than mine
This question already has answers here:
Javascript Pangram Regex
(9 answers)
Closed 5 months ago.
Summary of problem:
Essentially I want to perform the following function:
function isPangram(string){
if (all characters a - z are present in the string) {
return true;
} else {
return false;
}
}
Here's what I've tried thus far:
function isPangram(string){
if (string.contains(/[a-z]/)) {
return true;
} else {
return false;
}
}
function isPangram(string){
if (string.matchAll(/[a-z]/) {
return true;
} else {
return false;
}
}
function isPangram(string){
for (let i = 0; i < string.length; i++) {
if (string[i] = /[a-z]/) {
return true;
} else {
return false;
}
}
I've laid out the problem and I have the solution but I'm unaware of the proper syntax that allows me to get the solution I'm looking for. So! I'm asking for syntax recommendations that can help lead me in the right direction. I can struggle from there~
Try using this expression:
new Set("<your_string>".toLowerCase().replace(/[^a-z]/g, "") ).size === 26
A way to accomplish that could be iterating all characters in test string, and match each character against an "alphabet" array. If character is found, then it gets removed from the alphabet.
When all characters are scanned, if alphabet doesn't contain any elements, it means test string contained all characters in the alphabet.
const alphabet = []
//const testString = '123badcfehgjilknmporqtsvuxwzy000'
const testString = '123badcfehgtsvuxwzy000'
// POPULATE alphabet WITH ASCII CHARACTERS CODES FROM a TO z
for (let i = 97; i < 123; i++) {
alphabet.push(i)
}
// SCAN ALL CHARACTERS IN testString
for (let i = 0; i < testString.length; i++) {
let pos = alphabet.indexOf(testString[i].charCodeAt(0))
if (pos != -1) {
// IF CURRENT CHARACTER IS PRESENT IN OUR alphabet ARRAY, REMOVE IT
alphabet.splice(pos, 1)
}
}
if (alphabet.length == 0) {
console.log('All alphabet letters found in test string')
} else {
console.log('These alphabet letters were not found: ', alphabet.map(c => String.fromCharCode(c)) )
}
This is my first post so I hope im doing this correctly.
I am taking a coding class and we were asked to make a piece of code that will ask for the input of a phrase, and will return in the console that phrase with the capital letters moved to the front, but still in the same order. Then print to the console this reordered phrase. (We aren't allowed to use arrays)
For example:
Inputting "HeLLoTherE" would return "HLLTEeoher"
However the problem is im having issues understanding how to write this code. How can I make the code select these capital letters and move them to the front? using .toUpperCase()? How can i make that select the letter and move it in front of the rest?
If someone could show me an example of how this is done and explain it a little i would greatly appreciate it :)
You might just start with a the most straight forward algorithm to get something working.
let value = "HeLLoTherE";
let result = "";
for (let char of value) {
if (char >= "A" && char <= "Z") {
result += char;
}
}
for (let char of value) {
if (char >= "a" && char <= "z") {
result += char;
}
}
console.log(result);
You could then consolidate the 2 loops by combining the conditions.
let value = "HeLLoTherE";
let upper = "";
let lower = "";
for (let char of value) {
if (char >= "A" && char <= "Z") {
upper += char;
} else if (char >= "a" && char <= "z") {
lower += char;
}
}
console.log(upper + lower);
Another way of solving this would be to use regex.
var value = "HeLLoTherE";
var upper = value.replace(/[^A-Z]*/g, "");
var lower = value.replace(/[^a-z]*/g, "");
console.log(upper + lower);
Well, you are not able to use arrays, which makes it a little bit difficult, however you can still do sommething.
Although I'm using a for loop, I'm not actually using arrays. Since strings allows the [] operator, you can use an index to select each character of the string and check if it's lowercase or uppercase.
In addition, you said you need to mantain the order of uppercase letters, so you couldn't just do newStr = upper + newStr, because it would revert the original order. So, I used the string.prototype.substring() to insert the uppercase character where it should be.
const str = "HeLLoTherE";
const moveUpperToFront = (target) => {
// Strings are immutable in js, so you cannot move one character
// to the front without using a new string.
let newStr = "";
// Number of uppercase letters that appeared.
// It's necessary because you need to mantain the original order
let upperNumber = 0;
// Iterate each character from beginning
for (let i = 0; i < str.length; ++i) {
// Is there an uppercase letter?
if (str[i].charCodeAt() >= 65 && str[i].charCodeAt() <= 90) {
newStr =
newStr.substring(0, upperNumber) +
str[i] +
newStr.substring(upperNumber, newStr.length);
++upperNumber;
}
// No uppercase letter?
else
newStr += str[i];
}
return newStr;
};
console.log(moveUpperToFront(str));
Following a solution which uses a for...of loop to iterate the input. It splits the input into capital and lowercase literals and then merges back together:
const exampleLiteral = 'HeLLoTherE';
const isUppercase = (literal) => literal === literal.toUpperCase() && literal !== literal.toLowerCase();
const prefixCapitalLetters = (literal) => {
let capitalLetters = '';
let lowerLetters = '';
for (let letter of literal) {
if(isUppercase(letter)) {
capitalLetters = capitalLetters.concat(letter);
continue;
}
lowerLetters = lowerLetters.concat(letter);
};
return capitalLetters+lowerLetters;
}
console.log(prefixCapitalLetters(exampleLiteral));
This is really not a very hard problem:
function rearrange(str) {
let result = "";
for (let c of str)
if (c >= 'A' && c <= 'Z')
result += c;
for (let c of str)
if (c < 'A' || c > 'Z')
result += c;
return result;
}
console.log(rearrange("Hello World, It Is A Beautiful Morning!"));
Find the upper-case characters, and add them to a result string. Then go back and find the other characters, and add them at the end. By looping through without any sorting, just simple iteration from start to finish, the order is preserved (other than the upper-case stuff).
The truly hard part of this would be coming up with a way to detect "upper-case" letters across all of Unicode. Some languages (well, orthographies) don't have the concept at all. JavaScript has ways that are more and less convenient to deal with that, but I suspect for the classroom material the OP has available so far, given the nature of the original question, such regex trickery would probably be inappropriate for an answer.
This answer tries to achieve the desired objective without using "arrays". It does use back-ticks, but that can be replaced with a simple string-concatenation if required.
Code Snippet
// move upper-case letters while
// keeping relative order same
const capsWithOrder = str => {
// initialize result variables
let capsOnly = "", restAll = "";
// iterate over the given string input
for (let i = 0; i < str.length; i++) {
// if character at index "i" is upper-case
// then, concatenate character to "capsOnly"
// else, concatenate to "restAll"
if (str[i] === str[i].toUpperCase()) capsOnly += str[i];
else restAll += str[i];
};
// after iterating over all characters in string-input
// return capsOnly concatenated with restAll
return `${capsOnly}${restAll}`;
};
console.log(capsWithOrder("HeLLoTherE"));
Explanation
Inline comments added in the snippet above.
Something like this
const string1 = 'HeLLoTherE'
const transform = string => {
const lower = string.split('').filter(c => c.charCodeAt() > 'a'.charCodeAt())
const upper = string.split('').filter(c => c.charCodeAt() < 'Z'.charCodeAt())
return [...upper, ...lower].join('')
}
console.log(transform(string1))
I think that must be work.
const sort = [
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''),
'abcdefghijklmnopqrstuvwxyz'.split('')
]
function listByValue(string) {
string = [...string];
let ret = [];
for (let i in sort)
ret = [...ret,...string.filter(e=>sort[i].includes(e))];
return ret.join('')
}
This question already has answers here:
return the first non repeating character in a string in javascript
(32 answers)
Closed 1 year ago.
I tried to solve the problem below on a site, but they keep saying that something is not right when I reach certain tests.
Given a string s consisting of small English letters, find and return the first instance of a non-repeating character in it. If there is no such character, return "_".
I tried this
function firstNotRepeatingCharacter(s) {
let strArr = s.replace(" ", "").split(""),
newArr = [];
for (let i = 0; i < strArr.length; i++) {
newArr = strArr.filter(lol => lol === strArr[i]);
if (newArr.length === 1) {
return newArr[0];
};
};
return "_";
};
console.log(firstNotRepeatingCharacter("abacabad"));
It works for 16 out of 19 tests. why not all
Thanks all!
I've found an answer.
function firstNotRepeatingCharacter(s) {
let strArr = s.replace(" ", "").split("");
for (let str of strArr)
if(strArr.indexOf(str) == strArr.lastIndexOf(str))
return str;
return "_";
};
console.log(firstNotRepeatingCharacter("abacabad"));
another approach with a better time complexity:
function firstNotRepeatingCharacter(s) {
const seenBefore = new Set();
let result = "_";
for (let i = s.length; i--;) {
const char = s.charAt(i);
if (seenBefore.has(char)) continue;
seenBefore.add(char);
result = char;
}
return result;
}
console.log(firstNotRepeatingCharacter("abacabad"));
This is one of my function for a calculator project. First I needed to convert the input string into an array, and do the operation later. (assuming that input has only numbers and '+' sign for now.
My question here is, how do I improve this code? What are the other ways to deal with this problem? (Time complexity, cleanness, shorter code.......whatever)
function convertArray(input) {
let array = [];
let num = "";
for (let i = 0; i < input.length; i++) {
if (input.charAt(i) == '+') {
array.push(input.charAt(i));
} else {
do {
num += input.charAt(i);
i++;
} while (i < input.length && input.charAt(i) !== '+');
array.push(num);
num = "";
i--;
}
}
return array;
}
console.log(convertArray("10+2+3000+70+1"));
You could split with a group. this add the group as well to the array.
For other calculation signs, you could add them to the brackets.
const convertArray = string => string.split(/([+])/);
console.log(convertArray("10+2+3000+70+1"));
const q = prompt('Sum?');
alert('Answer: ' + eval(q));
Would not recommend using eval, but if all you need is a quick and dirty trick, it works.
Personally, I'd recommend a library such as Math.js, but any will do.
If you really need to do this by yourself for a project, I'd recommend checking out the answers here: Evaluating a string as a mathematical expression in JavaScript.
Hope you succeed in whatever you're planning on doing.
It seems the complexity must have something to do with your wish to determing operators. In your code you just push them all into the array. To do that is like
const re = /((\d+)|([^\d]+))/g
const convertArray = str => {
let match, arr=[];
while (match = re.exec(str)) {
arr.push(match[1]) // here you can determine if you have an operator
console.log(match[1],"Operator?",!/^\d+$/.test(match[1]))
}
return arr
}
const str = "10+2+3000+70+1";
console.log(convertArray(str));