How do you reverse a string in place (or in-place) in JavaScript when it is passed to a function with a return statement, without using built-in functions (.reverse()<
Strings themselves are immutable, but you can easily create a reversed copy with the following code:
function reverseString(str) {
var strArray = str.split("");
strArray.reverse();
var strReverse = strArray.join("");
return strReverse;
}
reverseString("hello");
Seems like I'm 3 years late to the party...
Unfortunately you can't as has been pointed out. See Are JavaScript strings immutable? Do I need a "string builder" in JavaScript?
The next best thing you can do is to create a "view" or "wrapper", which takes a string and reimplements whatever parts of the string API you are using, but pretending the string is reversed. For example:
var identity = function(x){return x};
function LazyString(s) {
this.original = s;
this.length = s.length;
this.start = 0; this.stop = this.length; this.dir = 1; // "virtual" slicing
// (dir=-1 if reversed)
this._caseTransform = identity;
}
// syntactic sugar to create new object:
function S(s) {
return new LazyString(s);
}
//We now implement a `"...".reversed` which toggles a flag which will change our math:
(function(){ // begin anonymous scope
var x = LazyString.prototype;
// Addition to the String API
x.reversed = function() {
var s = new LazyString(this.original);
s.start = this.stop - this.dir;
s.stop = this.start - this.dir;
s.dir = -1*this.dir;
s.length = this.length;
s._caseTransform = this._caseTransform;
return s;
}
//We also override string coercion for some extra versatility (not really necessary):
// OVERRIDE STRING COERCION
// - for string concatenation e.g. "abc"+reversed("abc")
x.toString = function() {
if (typeof this._realized == 'undefined') { // cached, to avoid recalculation
this._realized = this.dir==1 ?
this.original.slice(this.start,this.stop) :
this.original.slice(this.stop+1,this.start+1).split("").reverse().join("");
this._realized = this._caseTransform.call(this._realized, this._realized);
}
return this._realized;
}
//Now we reimplement the String API by doing some math:
// String API:
// Do some math to figure out which character we really want
x.charAt = function(i) {
return this.slice(i, i+1).toString();
}
x.charCodeAt = function(i) {
return this.slice(i, i+1).toString().charCodeAt(0);
}
// Slicing functions:
x.slice = function(start,stop) {
// lazy chaining version of https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/slice
if (stop===undefined)
stop = this.length;
var relativeStart = start<0 ? this.length+start : start;
var relativeStop = stop<0 ? this.length+stop : stop;
if (relativeStart >= this.length)
relativeStart = this.length;
if (relativeStart < 0)
relativeStart = 0;
if (relativeStop > this.length)
relativeStop = this.length;
if (relativeStop < 0)
relativeStop = 0;
if (relativeStop < relativeStart)
relativeStop = relativeStart;
var s = new LazyString(this.original);
s.length = relativeStop - relativeStart;
s.start = this.start + this.dir*relativeStart;
s.stop = s.start + this.dir*s.length;
s.dir = this.dir;
//console.log([this.start,this.stop,this.dir,this.length], [s.start,s.stop,s.dir,s.length])
s._caseTransform = this._caseTransform;
return s;
}
x.substring = function() {
// ...
}
x.substr = function() {
// ...
}
//Miscellaneous functions:
// Iterative search
x.indexOf = function(value) {
for(var i=0; i<this.length; i++)
if (value==this.charAt(i))
return i;
return -1;
}
x.lastIndexOf = function() {
for(var i=this.length-1; i>=0; i--)
if (value==this.charAt(i))
return i;
return -1;
}
// The following functions are too complicated to reimplement easily.
// Instead just realize the slice and do it the usual non-in-place way.
x.match = function() {
var s = this.toString();
return s.apply(s, arguments);
}
x.replace = function() {
var s = this.toString();
return s.apply(s, arguments);
}
x.search = function() {
var s = this.toString();
return s.apply(s, arguments);
}
x.split = function() {
var s = this.toString();
return s.apply(s, arguments);
}
// Case transforms:
x.toLowerCase = function() {
var s = new LazyString(this.original);
s._caseTransform = ''.toLowerCase;
s.start=this.start; s.stop=this.stop; s.dir=this.dir; s.length=this.length;
return s;
}
x.toUpperCase = function() {
var s = new LazyString(this.original);
s._caseTransform = ''.toUpperCase;
s.start=this.start; s.stop=this.stop; s.dir=this.dir; s.length=this.length;
return s;
}
})() // end anonymous scope
Demo:
> r = S('abcABC')
LazyString
original: "abcABC"
__proto__: LazyString
> r.charAt(1); // doesn't reverse string!!! (good if very long)
"B"
> r.toLowerCase() // must reverse string, so does so
"cbacba"
> r.toUpperCase() // string already reversed: no extra work
"CBACBA"
> r + '-demo-' + r // natural coercion, string already reversed: no extra work
"CBAcba-demo-CBAcba"
The kicker -- the following is done in-place by pure math, visiting each character only once, and only if necessary:
> 'demo: ' + S('0123456789abcdef').slice(3).reversed().slice(1,-1).toUpperCase()
"demo: EDCBA987654"
> S('0123456789ABCDEF').slice(3).reversed().slice(1,-1).toLowerCase().charAt(3)
"b"
This yields significant savings if applied to a very large string, if you are only taking a relatively small slice thereof.
Whether this is worth it (over reversing-as-a-copy like in most programming languages) highly depends on your use case and how efficiently you reimplement the string API. For example if all you want is to do string index manipulation, or take small slice
s or substr
s, this will save you space and time. If you're planning on printing large reversed slices or substrings however, the savings may be small indeed, even worse than having done a full copy. Your "reversed" string will also not have the type string
, though you might be able to fake this with prototyping.
The above demo implementation creates a new object of type ReversedString. It is prototyped, and therefore fairly efficient, with almost minimal work and minimal space overhead (prototype definitions are shared). It is a lazy implementation involving deferred slicing. Whenever you perform a function like .slice
or .reversed
, it will perform index mathematics. Finally when you extract data (by implicitly calling .toString()
or .charCodeAt(...)
or something), it will apply those in a "smart" manner, touching the least data possible.
Note: the above string API is an example, and may not be implemented perfectly. You also can use just 1-2 functions which you need.
During an interview, I was asked to reverse a string without using any variables or native methods. This is my favorite implementation:
function reverseString(str) {
return str === '' ? '' : reverseString(str.slice(1)) + str[0];
}
String.prototype.reverse_string=function() {return this.split("").reverse().join("");}
or
String.prototype.reverse_string = function() {
var s = "";
var i = this.length;
while (i>0) {
s += this.substring(i-1,i);
i--;
}
return s;
}
There are Multiple ways of doing it, you may check the following,
1. Traditional for loop(incrementing):
function reverseString(str){
let stringRev ="";
for(let i= 0; i<str.length; i++){
stringRev = str[i]+stringRev;
}
return stringRev;
}
alert(reverseString("Hello World!"));
2. Traditional for loop(decrementing):
function reverseString(str){
let revstr = "";
for(let i = str.length-1; i>=0; i--){
revstr = revstr+ str[i];
}
return revstr;
}
alert(reverseString("Hello World!"));
3. Using for-of loop
function reverseString(str){
let strn ="";
for(let char of str){
strn = char + strn;
}
return strn;
}
alert(reverseString("Get well soon"));
4. Using the forEach/ high order array method:
function reverseString(str){
let revSrring = "";
str.split("").forEach(function(char){
revSrring = char + revSrring;
});
return revSrring;
}
alert(reverseString("Learning JavaScript"));
5. ES6 standard:
function reverseString(str){
let revSrring = "";
str.split("").forEach(char => revSrring = char + revSrring);
return revSrring;
}
alert(reverseString("Learning JavaScript"));
6. The latest way:
function reverseString(str){
return str.split("").reduce(function(revString, char){
return char + revString;
}, "");
}
alert(reverseString("Learning JavaScript"));
7. You may also get the result using the following,
function reverseString(str){
return str.split("").reduce((revString, char)=> char + revString, "");
}
alert(reverseString("Learning JavaScript"));
If you don't want to use any built in function. Try this
var string = 'abcdefg';
var newstring = '';
for(let i = 0; i < string.length; i++){
newstring = string[i] += newstring;
}
console.log(newstring);