Reversing a string in JS - javascript

In JavaScript, what would be the most simple way to reverse a string of characters? Because I am a student with brain dysfunctions that doesn't allow me to think straight and my code needs to be as simple as possible.

return s.split('').reverse().join('');

Above answer will work just fine; it is probably the simplest way.
Just to add a few words..
split() method splits a string into an array.
reverse() method reverses an array.
join() method joins elements into a string.
So we get
s.split('').reverse().join('');
It splits the string into an array, reverses and puts it back together from an array into a string.
Here is a solution using recursion:
function reverseString(s) {
return (s === '') ? '' : reverseString(s.substr(1)) + s.charAt(0);
}
The function recursively calls itself, where given string is passed as an argument (except for the first character) It will continue iterate until until it runs out of input. As a result we have a reversed string.

This one works as well, it's not as dense as the previous mentioned tho.
Here's the jsfiddle
function join(array, con) {
con = con ? con : "";
var str = "";
for (var i = 0; i < array.length; i++) {
str += array[i] + con;
}
return str;
}
function reverse(str) {
var newStr = [];
for (var i = 0; i < str.length / 2; i++) {
var temp = str[i];
newStr[i] = str[str.length - i - 1];
newStr[str.length - i - 1] = temp;
}
return join(newStr, "");
}
document.write(reverse("FooBar"));

Method - 1
Convert string to array using Array.from
call reverse on array
call join on array for converting into string
Method - 2
Using Array.from and reduceRight
const str = "stack overflow";
const rev_str = Array.from(str).reverse().join('');
console.log(rev_str)
// Alternate way
const rev_str2 = Array.from(str).reduceRight((acc, curr) => `${acc}${curr}`, '');
console.log(rev_str2)

Related

Can a JavaScript loop, upon the second iteration, iterate from the result of the prior iteration?

I just joined Stack Overflow and this is my first post so please do not hesitate to let me know if I am doing anything wrong.
I was presented with a challenge to create a function that accepts a string and calls another given function which swaps indices until the string is returned backwards.
I have gotten as far as below:
//given function
function swap(str, first, last){
str = str.split('');
let firstIndex = str[first];
str[first] = str[last];
str[last] = firstIndex;
str = str.join("").toString()
return str;
}
//my function
let word = "Hello"
function reverseSwap(str) {
let result = ""
for (let i = 0; i < str.length/2; i++) {
result += swap(str, i, str.length -1 - i);
}
return result;
}
console.log(reverseSwap(word))
This however returns "oellHHlleoHello", because each iteration swaps indices from the original string then concatenates. Is it possible, upon the second iteration, to have the loop iterate from the result of the prior iteration so the following occurs?:
result of first iteration: swap(word, 0, 4) which returns "oellH"
second iteration uses "oellH" instead of "Hello" to swap(1, 3) which returns "olleH"
Then, swap(2,2) which doesn't change anything.
It's not working because
Don't += add all new strings to your result. (This will append each swap string to your result.)
You have to manipulate always the "result" string. (You want to do a swap always on the updated version of the string. Not the original one)
Here is a simple solution:
function swap(str, first, last) {
str = str.split("");
let firstIndex = str[first];
str[first] = str[last];
str[last] = firstIndex;
str = str.join("").toString();
return str;
}
let word = "Hello";
function reverseSwap(str) {
for (let i = 0; i < str.length / 2; i++) {
str = swap(str, i, str.length - 1 - i);
}
return str;
}
console.log(reverseSwap(word));

Concat method returns empty string while + operator works fine [duplicate]

This question already has an answer here:
String Concat not working in scope JS
(1 answer)
Closed 1 year ago.
I am writing a program to concatenate a string to make it repeat a number of times but on using concat method it always returns an empty string. I have solved the problem using + operator. But I still want to figure why concat is returning empty string.
Here is the code
let repeatStr = (str, num) => {
let newStr = '';
for(let i = 0; i < num; i++){
newStr.concat(str);
}
return newStr;
}
I believe it is because concat method does not modify the string in-place, and you need to assign its result to some variable. If instead you replace that line in your code with newStr = newStr.concat(str); it should work fine.
This is because .concat() returns a new string, and the original is unmodified. You can reassign to the same variable.
Note: You can also use the + operator.
let repeatStr = (str, num) => {
let newStr = '';
for(let i = 0; i < num; i++){
//newStr = newStr.concat(str); //Both work
newStr += str;
}
return newStr;
}
console.log(repeatStr('x',3));
If you check the definition of concat in MDN
The concat() method concatenates the string arguments to the
calling string and returns a new string.
that is means that it doesn't change the old value of your variable
so all you need is to re-assign your variable with the new value
let repeatStr = (str, num) => {
let newStr = '';
for(let i = 0; i < num; i++){
newStr = newStr.concat(str);
}
return newStr;
}
console.log(repeatStr('welcome', 2))
there is another simple solution you could use repeat function it used for this purpose like this
console.log("welcome".repeat(3))

How to get odd and even position characters from a string?

I'm trying to figure out how to remove every second character (starting from the first one) from a string in Javascript.
For example, the string "This is a test!" should become "hsi etTi sats!"
I also want to save every deleted character into another array.
I have tried using replace method and splice method, but wasn't able to get them to work properly. Mostly because replace only replaces the first character.
function encrypt(text, n) {
if (text === "NULL") return n;
if (n <= 0) return text;
var encArr = [];
var newString = text.split("");
var j = 0;
for (var i = 0; i < text.length; i += 2) {
encArr[j++] = text[i];
newString.splice(i, 1); // this line doesn't work properly
}
}
You could reduce the characters of the string and group them to separate arrays using the % operator. Use destructuring to get the 2D array returned to separate variables
let str = "This is a test!";
const [even, odd] = [...str].reduce((r,char,i) => (r[i%2].push(char), r), [[],[]])
console.log(odd.join(''))
console.log(even.join(''))
Using a for loop:
let str = "This is a test!",
odd = [],
even = [];
for (var i = 0; i < str.length; i++) {
i % 2 === 0
? even.push(str[i])
: odd.push(str[i])
}
console.log(odd.join(''))
console.log(even.join(''))
It would probably be easier to use a regular expression and .replace: capture two characters in separate capturing groups, add the first character to a string, and replace with the second character. Then, you'll have first half of the output you need in one string, and the second in another: just concatenate them together and return:
function encrypt(text) {
let removedText = '';
const replacedText1 = text.replace(/(.)(.)?/g, (_, firstChar, secondChar) => {
// in case the match was at the end of the string,
// and the string has an odd number of characters:
if (!secondChar) secondChar = '';
// remove the firstChar from the string, while adding it to removedText:
removedText += firstChar;
return secondChar;
});
return replacedText1 + removedText;
}
console.log(encrypt('This is a test!'));
Pretty simple with .reduce() to create the two arrays you seem to want.
function encrypt(text) {
return text.split("")
.reduce(({odd, even}, c, i) =>
i % 2 ? {odd: [...odd, c], even} : {odd, even: [...even, c]}
, {odd: [], even: []})
}
console.log(encrypt("This is a test!"));
They can be converted to strings by using .join("") if you desire.
I think you were on the right track. What you missed is replace is using either a string or RegExp.
The replace() method returns a new string with some or all matches of a pattern replaced by a replacement. The pattern can be a string or a RegExp, and the replacement can be a string or a function to be called for each match. If pattern is a string, only the first occurrence will be replaced.
Source: String.prototype.replace()
If you are replacing a value (and not a regular expression), only the first instance of the value will be replaced. To replace all occurrences of a specified value, use the global (g) modifier
Source: JavaScript String replace() Method
So my suggestion would be to continue still with replace and pass the right RegExp to the function, I guess you can figure out from this example - this removes every second occurrence for char 't':
let count = 0;
let testString = 'test test test test';
console.log('original', testString);
// global modifier in RegExp
let result = testString.replace(/t/g, function (match) {
count++;
return (count % 2 === 0) ? '' : match;
});
console.log('removed', result);
like this?
var text = "This is a test!"
var result = ""
var rest = ""
for(var i = 0; i < text.length; i++){
if( (i%2) != 0 ){
result += text[i]
} else{
rest += text[i]
}
}
console.log(result+rest)
Maybe with split, filter and join:
const remaining = myString.split('').filter((char, i) => i % 2 !== 0).join('');
const deleted = myString.split('').filter((char, i) => i % 2 === 0).join('');
You could take an array and splice and push each second item to the end of the array.
function encrypt(string) {
var array = [...string],
i = 0,
l = array.length >> 1;
while (i <= l) array.push(array.splice(i++, 1)[0]);
return array.join('');
}
console.log(encrypt("This is a test!"));
function encrypt(text) {
text = text.split("");
var removed = []
var encrypted = text.filter((letter, index) => {
if(index % 2 == 0){
removed.push(letter)
return false;
}
return true
}).join("")
return {
full: encrypted + removed.join(""),
encrypted: encrypted,
removed: removed
}
}
console.log(encrypt("This is a test!"))
Splice does not work, because if you remove an element from an array in for loop indexes most probably will be wrong when removing another element.
I don't know how much you care about performance, but using regex is not very efficient.
Simple test for quite a long string shows that using filter function is on average about 3 times faster, which can make quite a difference when performed on very long strings or on many, many shorts ones.
function test(func, n){
var text = "";
for(var i = 0; i < n; ++i){
text += "a";
}
var start = new Date().getTime();
func(text);
var end = new Date().getTime();
var time = (end-start) / 1000.0;
console.log(func.name, " took ", time, " seconds")
return time;
}
function encryptREGEX(text) {
let removedText = '';
const replacedText1 = text.replace(/(.)(.)?/g, (_, firstChar, secondChar) => {
// in case the match was at the end of the string,
// and the string has an odd number of characters:
if (!secondChar) secondChar = '';
// remove the firstChar from the string, while adding it to removedText:
removedText += firstChar;
return secondChar;
});
return replacedText1 + removedText;
}
function encrypt(text) {
text = text.split("");
var removed = "";
var encrypted = text.filter((letter, index) => {
if(index % 2 == 0){
removed += letter;
return false;
}
return true
}).join("")
return encrypted + removed
}
var timeREGEX = test(encryptREGEX, 10000000);
var timeFilter = test(encrypt, 10000000);
console.log("Using filter is faster ", timeREGEX/timeFilter, " times")
Using actually an array for storing removed letters and then joining them is much more efficient, than using a string and concatenating letters to it.
I changed an array to string in filter solution to make it the same like in regex solution, so they are more comparable.

Why can't I swap characters in a javascript string?

I am trying to swap first and last characters of array.But javascript is not letting me swap.
I don't want to use any built in function.
function swap(arr, first, last){
var temp = arr[first];
arr[first] = arr[last];
arr[last] = temp;
}
Because strings are immutable.
The array notation is just that: a notation, a shortcut of charAt method. You can use it to get characters by position, but not to set them.
So if you want to change some characters, you must split the string into parts, and build the desired new string from them:
function swapStr(str, first, last){
return str.substr(0, first)
+ str[last]
+ str.substring(first+1, last)
+ str[first]
+ str.substr(last+1);
}
Alternatively, you can convert the string to an array:
function swapStr(str, first, last){
var arr = str.split('');
swap(arr, first, last); // Your swap function
return arr.join('');
}
Let me offer my side of what I understood: swapping items of an array could be something like:
var myFish = ["angel", "clown", "mandarin", "surgeon"];
var popped = myFish.pop();
myFish.unshift(popped) // results in ["surgeon", "angel", "clown", "mandarin"]
Regarding swaping first and last letters of an strings could be done using Regular Expression using something like:
"mandarin".replace(/^(\w)(.*)(\w)$/,"$3$2$1")// outputs nandarim ==> m is last character and n is first letter
I just ran your code right out of Chrome, and it seemed to work find for me. Make sure the indices you pass in for "first" and "last" are correct (remember JavaScript is 0-index based). You might want to also try using console.log in order to print out certain variables and debug if it still doesn't work for you.
EDIT: I didn't realize you were trying to manipulate a String; I thought you just meant an array of characters or values.
function swapStr(str, first, last) {
if (first == last) {
return str;
}
if (last < first) {
var temp = last;
last = first;
first = temp;
}
if (first >= str.length) {
return str;
}
return str.substring(0, first) +
str[last] +
str.substring(first + 1, last) +
str[first] +
str.substring(last + 1);
}
Swap characters inside a string requires the string to convert into an array, then the array can be converted into string again:
function swap(arr, first, last){
arr = arr.split(''); //to array
var temp = arr[first];
arr[first] = arr[last];
arr[last] = temp;
arr = arr.join("").toString() //to string
return arr;
}
Following usage:
str = "ABCDE"
str = swap(str,1,2)
console.log(str) //print "ACBDE"
I hope this piece of code will help somebody.
var word = "DED MOROZ";
var arr = word.split('');
for (var i = 0; i < arr.length/2; i++) {
var temp = arr[i];
arr[i] = arr[arr.length - i - 1];
arr[word.length - i - 1] = temp;
}
console.log(arr.join(""));
Run this code and your characters will be swapped.

Swap Case on javascript

I made a script that changes the case, but result from using it on text is exactly the same text, without a single change. Can someone explain this?
var swapCase = function(letters){
for(var i = 0; i<letters.length; i++){
if(letters[i] === letters[i].toLowerCase()){
letters[i] = letters[i].toUpperCase();
}else {
letters[i] = letters[i].toLowerCase();
}
}
console.log(letters);
}
var text = 'So, today we have REALLY good day';
swapCase(text);
Like Ian said, you need to build a new string.
var swapCase = function(letters){
var newLetters = "";
for(var i = 0; i<letters.length; i++){
if(letters[i] === letters[i].toLowerCase()){
newLetters += letters[i].toUpperCase();
}else {
newLetters += letters[i].toLowerCase();
}
}
console.log(newLetters);
return newLetters;
}
var text = 'So, today we have REALLY good day';
var swappedText = swapCase(text); // "sO, TODAY WE HAVE really GOOD DAY"
You can use this simple solution.
var text = 'So, today we have REALLY good day';
var ans = text.split('').map(function(c){
return c === c.toUpperCase()
? c.toLowerCase()
: c.toUpperCase()
}).join('')
console.log(ans)
Using ES6
var text = 'So, today we have REALLY good day';
var ans = text.split('')
.map((c) =>
c === c.toUpperCase()
? c.toLowerCase()
: c.toUpperCase()
).join('')
console.log(ans)
guys! Get a little simplier code:
string.replace(/\w{1}/g, function(val){
return val === val.toLowerCase() ? val.toUpperCase() : val.toLowerCase();
});
Here is an alternative approach that uses bitwise XOR operator ^.
I feel this is more elegant than using toUppserCase/ toLowerCase methods
"So, today we have REALLY good day"
.split("")
.map((x) => /[A-z]/.test(x) ? String.fromCharCode(x.charCodeAt(0) ^ 32) : x)
.join("")
Explanation
So we first split array and then use map function to perform mutations on each char, we then join the array back together.
Inside the map function a RegEx tests if the value is an alphabet character: /[A-z]/.test(x) if it is then we use XOR operator ^ to shift bits. This is what inverts the casing of character. charCodeAt convert char to UTF-16 code. XOR (^) operator flips the char. String.fromCharCode converts code back to char.
If RegEx gives false (not an ABC char) then the ternary operator will return character as is.
References:
String.fromCharCode
charCodeAt
Bitwise operators
Ternary operator
Map function
One liner for short mode code wars:
let str = "hELLO wORLD"
str.split("").map(l=>l==l.toLowerCase()?l.toUpperCase():l.toLowerCase()).join("")
const swapCase = (myString) => {
let newString = ''; // Create new empty string
if (myString.match(/[a-zA-Z]/)) { // ensure the parameter actually has letters, using match() method and passing regular expression.
for (let x of myString) {
x == x.toLowerCase() ? x = x.toUpperCase() : x = x.toLowerCase();
newString += x; // add on each conversion to the new string
}
} else {
return 'String is empty, or there are no letters to swap.' // In case parameter contains no letters
}
return newString; // output new string
}
// Test the function.
console.log(swapCase('Work Today Was Fun')); // Output: wORK tODAY wAS fUN
console.log(swapCase('87837874---ABCxyz')); // Output: 87837874---abcXYZ
console.log(swapCase('')); // Output: String is empty, or there are no letters to swap.
console.log(swapCase('12345')); // Output: String is empty, or there are no letters to swap.
// This one will fail. But, you can wrap it with if(typeof myString != 'number') to prevent match() method from running and prevent errors.
// console.log(swapCase(12345));
This is a solution that uses regular expressions. It matches each word-char globally, and then performs a function on that matched group.
function swapCase(letters) {
return letters.replace( /\w/g, function(c) {
if (c === c.toLowerCase()) {
return c.toUpperCase();
} else {
return c.toLowerCase();
}
});
}
#this is a program to convert uppercase to lowercase and vise versa and returns the string.
function main(input) {
var i=0;
var string ='';
var arr= [];
while(i<input.length){
string = input.charAt(i);
if(string == string.toUpperCase()){
string = string.toLowerCase();
arr += string;
}else {
string = string.toUpperCase();
arr += string;
}
i++;
}
console.log(arr);
}
Split the string and use the map function to swap the case of letters.
We'll get the array from #1.
Join the array using join function.
`
let str = 'The Quick Brown Fox Jump Over A Crazy Dog'
let swapedStrArray = str.split('').map(a => {
return a === a.toUpperCase() ? a.toLowerCase() : a.toUpperCase()
})
//join the swapedStrArray
swapedStrArray.join('')
console.log('swapedStrArray', swapedStrArray.join(''))
`
A new solution using map
let swappingCases = "So, today we have REALLY good day";
let swapping = swappingCases.split("").map(function(ele){
return ele === ele.toUpperCase()? ele.toLowerCase() : ele.toUpperCase();
}).join("");
console.log(swapping);
As a side note in addition to what has already been said, your original code could work with just some minor modifications: convert the string to an array of 1-character substrings (using split), process this array and convert it back to a string when you're done (using join).
NB: the idea here is to highlight the difference between accessing a character in a string (which can't be modified) and processing an array of substrings (which can be modified). Performance-wise, Fabricator's solution is probably better.
var swapCase = function(str){
var letters = str.split("");
for(var i = 0; i<letters.length; i++){
if(letters[i] === letters[i].toLowerCase()){
letters[i] = letters[i].toUpperCase();
}else {
letters[i] = letters[i].toLowerCase();
}
}
str = letters.join("");
console.log(str);
}
var text = 'So, today we have REALLY good day';
swapCase(text);

Categories

Resources