Javascript: What does this `Array(i+1)` do? - javascript

Hi I found a solution for a problem on codewars and I'm not sure what a piece of the syntax does. The function takes a string of characters, and based on the length, returns it in a certain fashion.
input = "abcd"; output = "A-Bb-Ccc-Dddd"
input = "gFkLM"; output = "G-Ff-Kkk-Llll-Mmmmm"
This guy posted this solution
function accum(str) {
var letters = str.split('');
var result = [];
for (var i = 0; i < letters.length; i++) {
result.push(letters[i].toUpperCase() + Array(i + 1).join(letters[i].toLowerCase()));
}
return result.join('-');
}
Kinda confused about the solution overall, but one thing is particularly nagging me. See that Array(i + 1) ? What does that do? Sorry, not a very easy thing to google.

I believe that this allocates an array of length i + 1. But more importantly, what is the code doing? You have to know what the join() function does... It concatenates elements in an array delimitated by the function argument. For example:
['one', 'two', 'three'].join(' ') === 'one two three'
In this case, the array is filled with undefined elements, so you get something like this:
[undefined].join('a') === ''
[undefined, undefined].join('b') === 'b'
[undefined, undefined, undefined].join('c') === 'cc'
[undefined, undefined, undefined, undefined].join('d') === 'ddd'

So in the beginning for statement, i starts out at 0. Now if you go inside the for statement where it says i+1, i would be 1. And then when the for loop updates and i equals 1, i+1 inside the for loop would equal 2. This process would continue for the length of the string. Hope this helps.

I have just checked
let x= Array(3);
console.log(x);
The output is [undefined, undefined, undefined]
So it actually creates array of size 3 with all the elements as undefined.
When we call join wit a character as param it creates a string with the same character repeating 2 times i.e (3-1).
console.log(x.join('a')); // logs aa

Commented code walk-though ....
function accum(str) {
/* converts string to character array.*/
var letters = str.split('');
/* variable to store result */
var result = [];
/* for each character concat (1.) + (2.) and push into results.
1. letters[i].toUpperCase() :
UPPER-CASE of the character.
2. Array(i + 1).join(letters[i].toLowerCase()) :
create an array with EMPTY SLOTS of length that is, +1 than the current index.
And join them to string with the current charater's LOWER-CASE as the separator.
Ex:
Index | ArrayLength, Array | Separator | Joined String
0 1, [null] 'a' ''
1 2, [null,null] 'b' 'b'
2 3, [null,null,null] 'c' 'cc'
3 4, [null,null,null,null] 'd' 'ddd'
NOTE:
Join on an array with EMPTY SLOTS, inserts the seperator inbetween the slot values.
Meaning, if N is the length of array. Then there will be N-1 seperators inserted into the joined string
*/
for (var i = 0; i < letters.length; i++) {
result.push(letters[i].toUpperCase() + Array(i + 1).join(letters[i].toLowerCase()));
}
/* finally join all sperated by '-' and return ...*/
return result.join('-');
}

Related

How to determine matched group's offset in JavaScript's replace? [duplicate]

I want to match a regex like /(a).(b)(c.)d/ with "aabccde", and get the following information back:
"a" at index = 0
"b" at index = 2
"cc" at index = 3
How can I do this? String.match returns list of matches and index of the start of the complete match, not index of every capture.
Edit: A test case which wouldn't work with plain indexOf
regex: /(a).(.)/
string: "aaa"
expected result: "a" at 0, "a" at 2
Note: The question is similar to Javascript Regex: How to find index of each subexpression?, but I cannot modify the regex to make every subexpression a capturing group.
There is currently a proposal (stage 4) to implement this in native Javascript:
RegExp Match Indices for ECMAScript
ECMAScript RegExp Match Indices provide additional information about the start and end indices of captured substrings relative to the start of the input string.
...We propose the adoption of an additional indices property on the array result (the substrings array) of RegExp.prototype.exec(). This property would itself be an indices array containing a pair of start and end indices for each captured substring. Any unmatched capture groups would be undefined, similar to their corresponding element in the substrings array. In addition, the indices array would itself have a groups property containing the start and end indices for each named capture group.
Here's an example of how things would work. The following snippets run without errors in, at least, Chrome:
const re1 = /a+(?<Z>z)?/d;
// indices are relative to start of the input string:
const s1 = "xaaaz";
const m1 = re1.exec(s1);
console.log(m1.indices[0][0]); // 1
console.log(m1.indices[0][1]); // 5
console.log(s1.slice(...m1.indices[0])); // "aaaz"
console.log(m1.indices[1][0]); // 4
console.log(m1.indices[1][1]); // 5
console.log(s1.slice(...m1.indices[1])); // "z"
console.log(m1.indices.groups["Z"][0]); // 4
console.log(m1.indices.groups["Z"][1]); // 5
console.log(s1.slice(...m1.indices.groups["Z"])); // "z"
// capture groups that are not matched return `undefined`:
const m2 = re1.exec("xaaay");
console.log(m2.indices[1]); // undefined
console.log(m2.indices.groups.Z); // undefined
So, for the code in the question, we could do:
const re = /(a).(b)(c.)d/d;
const str = 'aabccde';
const result = re.exec(str);
// indices[0], like result[0], describes the indices of the full match
const matchStart = result.indices[0][0];
result.forEach((matchedStr, i) => {
const [startIndex, endIndex] = result.indices[i];
console.log(`${matchedStr} from index ${startIndex} to ${endIndex} in the original string`);
console.log(`From index ${startIndex - matchStart} to ${endIndex - matchStart} relative to the match start\n-----`);
});
Output:
aabccd from index 0 to 6 in the original string
From index 0 to 6 relative to the match start
-----
a from index 0 to 1 in the original string
From index 0 to 1 relative to the match start
-----
b from index 2 to 3 in the original string
From index 2 to 3 relative to the match start
-----
cc from index 3 to 5 in the original string
From index 3 to 5 relative to the match start
Keep in mind that the indices array contains the indices of the matched groups relative to the start of the string, not relative to the start of the match.
A polyfill is available here.
I wrote MultiRegExp for this a while ago. As long as you don't have nested capture groups, it should do the trick. It works by inserting capture groups between those in your RegExp and using all the intermediate groups to calculate the requested group positions.
var exp = new MultiRegExp(/(a).(b)(c.)d/);
exp.exec("aabccde");
should return
{0: {index:0, text:'a'}, 1: {index:2, text:'b'}, 2: {index:3, text:'cc'}}
Live Version
I created a little regexp Parser which is also able to parse nested groups like a charm. It's small but huge. No really. Like Donalds hands. I would be really happy if someone could test it, so it will be battle tested. It can be found at: https://github.com/valorize/MultiRegExp2
Usage:
let regex = /a(?: )bc(def(ghi)xyz)/g;
let regex2 = new MultiRegExp2(regex);
let matches = regex2.execForAllGroups('ababa bcdefghixyzXXXX'));
Will output:
[ { match: 'defghixyz', start: 8, end: 17 },
{ match: 'ghi', start: 11, end: 14 } ]
Updated Answer: 2022
See String.prototype.matchAll
The matchAll() method matches the string against a regular expression and returns an iterator of matching results.
Each match is an array, with the matched text as the first item, and then one item for each parenthetical capture group. It also includes the extra properties index and input.
let regexp = /t(e)(st(\d?))/g;
let str = 'test1test2';
for (let match of str.matchAll(regexp)) {
console.log(match)
}
// => ['test1', 'e', 'st1', '1', index: 0, input: 'test1test2', groups: undefined]
// => ['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', groups: undefined]
Based on the ecma regular expression syntax I've written a parser respective an extension of the RegExp class which solves besides this problem (full indexed exec method) as well other limitations of the JavaScript RegExp implementation for example: Group based search & replace. You can test and download the implementation here (is as well available as NPM module).
The implementation works as follows (small example):
//Retrieve content and position of: opening-, closing tags and body content for: non-nested html-tags.
var pattern = '(<([^ >]+)[^>]*>)([^<]*)(<\\/\\2>)';
var str = '<html><code class="html plain">first</code><div class="content">second</div></html>';
var regex = new Regex(pattern, 'g');
var result = regex.exec(str);
console.log(5 === result.length);
console.log('<code class="html plain">first</code>'=== result[0]);
console.log('<code class="html plain">'=== result[1]);
console.log('first'=== result[3]);
console.log('</code>'=== result[4]);
console.log(5=== result.index.length);
console.log(6=== result.index[0]);
console.log(6=== result.index[1]);
console.log(31=== result.index[3]);
console.log(36=== result.index[4]);
I tried as well the implementation from #velop but the implementation seems buggy for example it does not handle backreferences correctly e.g. "/a(?: )bc(def(\1ghi)xyz)/g" - when adding paranthesis in front then the backreference \1 needs to be incremented accordingly (which is not the case in his implementation).
So, you have a text and a regular expression:
txt = "aabccde";
re = /(a).(b)(c.)d/;
The first step is to get the list of all substrings that match the regular expression:
subs = re.exec(txt);
Then, you can do a simple search on the text for each substring. You will have to keep in a variable the position of the last substring. I've named this variable cursor.
var cursor = subs.index;
for (var i = 1; i < subs.length; i++){
sub = subs[i];
index = txt.indexOf(sub, cursor);
cursor = index + sub.length;
console.log(sub + ' at index ' + index);
}
EDIT: Thanks to #nhahtdh, I've improved the mechanism and made a complete function:
String.prototype.matchIndex = function(re){
var res = [];
var subs = this.match(re);
for (var cursor = subs.index, l = subs.length, i = 1; i < l; i++){
var index = cursor;
if (i+1 !== l && subs[i] !== subs[i+1]) {
nextIndex = this.indexOf(subs[i+1], cursor);
while (true) {
currentIndex = this.indexOf(subs[i], index);
if (currentIndex !== -1 && currentIndex <= nextIndex)
index = currentIndex + 1;
else
break;
}
index--;
} else {
index = this.indexOf(subs[i], cursor);
}
cursor = index + subs[i].length;
res.push([subs[i], index]);
}
return res;
}
console.log("aabccde".matchIndex(/(a).(b)(c.)d/));
// [ [ 'a', 1 ], [ 'b', 2 ], [ 'cc', 3 ] ]
console.log("aaa".matchIndex(/(a).(.)/));
// [ [ 'a', 0 ], [ 'a', 1 ] ] <-- problem here
console.log("bababaaaaa".matchIndex(/(ba)+.(a*)/));
// [ [ 'ba', 4 ], [ 'aaa', 6 ] ]
I'm not exactly sure exactly what your requirements are for your search, but here's how you could get the desired output in your first example using Regex.exec() and a while-loop.
JavaScript
var myRe = /^a|b|c./g;
var str = "aabccde";
var myArray;
while ((myArray = myRe.exec(str)) !== null)
{
var msg = '"' + myArray[0] + '" ';
msg += "at index = " + (myRe.lastIndex - myArray[0].length);
console.log(msg);
}
Output
"a" at index = 0
"b" at index = 2
"cc" at index = 3
Using the lastIndex property, you can subtract the length of the currently matched string to obtain the starting index.

issue with substring indexing

Instructions for this kata:
In this Kata, we will check if a string contains consecutive letters as they appear in the English alphabet and if each letter occurs only once.
It seems that my code is indexing the strings differently per function call on this one. for example, on the first test "abcd", the starting index is shown as 0, which is correct, and on the second example, "himjlk", the
var subString = alphabet.substring(startIndex, length);
returns "g", instead of "h"
troubleshooting this section
var length = orderedString.length;
//startChar for string comparison
var startChar = orderedString.charAt(0);
//find index in aphabet of first character in orderedString.
var startIndex = alphabet.indexOf(startChar);
//create substring of alphabet with start index of orderedString and //orderedString.length
var subString = alphabet.substring(startIndex, length);
function solve(s) {
//alphabet string to check against
const alphabet = `abcdefghijklmnopqrstuvwxyz`;
//check s against alphabet
//empty array to order input string
var ordered = [];
//iterate through alphabet, checking against s
//and reorder input string to be alphabetized
for (var z in alphabet) {
var charToCheck = alphabet[z];
for (var i in s) {
if (charToCheck === s[i]) {
ordered.push(s[i]);
}
//break out of loop if lengths are the same
if (ordered.length === s.length) {
break;
}
}
if (ordered.length === s.length) {
break;
}
}
//join array back into string
var orderedString = ordered.join(``);
//length for future alphabet substring for comparison
var length = orderedString.length;
//startChar for string comparison
var startChar = orderedString.charAt(0);
//find index in aphabet of first character in orderedString.
var startIndex = alphabet.indexOf(startChar);
//create substring of alphabet with start index of orderedString and orderedString.length
var subString = alphabet.substring(startIndex, length);
//return if the two are a match
return subString == orderedString ? true : false;
}
console.log(solve("abdc")); //expected `true`
console.log(solve("himjlk")); // expected `true`
console.log(solve("abdc")); should provide the substring "abcd" and return true, which it does.
console.log(solve("himjlk")); should put together "hijklm" and return true, but instead gives me g based on index 6 of alphabet, not sure why it's doing this, should be index 7 "h" returns false based upon this error.
The problem is that you're using substring() instead of substr(). Though that might sound similar there's a difference.
With substring the second parameter doesn't determine the length as you might have expected. It's actually the index to stop.
That your function works as expected with the string abcd is pure coincidence since in this case the length from index 0 and the end index are the same.
function solve(s){
const alphabet = `abcdefghijklmnopqrstuvwxyz`;
var ordered = [];
for(var z in alphabet){
var charToCheck = alphabet[z];
for(var i in s){
if(charToCheck === s[i]){
ordered.push(s[i]);
}
if(ordered.length === s.length){ break; }
}
if(ordered.length === s.length){ break; }
}
var orderedString = ordered.join(``);
var length = orderedString.length;
var startChar = orderedString.charAt(0);
var startIndex = alphabet.indexOf(startChar);
var subString = alphabet.substr(startIndex, length);
return subString == orderedString ? true: false;
}
console.log(solve("himjlk"));
You approach is also correct. I am giving another solution using sort() and charCodeAt. Instead of getting the index and then breaking string into parts to compare just use includes()
function check(str){
let org = [...Array(26)].map((x,i) => String.fromCharCode(i + 97)).join('');
str = str.split('').sort((a, b) => a.charCodeAt(0) - b.charCodeAt(0)).join('');
return org.includes(str);
}
console.log(check("abdc"))//true
console.log(check("himjlk"));//true
console.log(check("himjlkp"));//false
Explanation:
Frist Line:
let org = [...Array(26)].map((x,i) => String.fromCharCode(i + 97)).join('');
is use to create string "abcd....xyz".
[...Array(26)] will create an array of 26(no of alphabets) undefined values.
map() is a function which takes a callback and the create an array based the values of previous. The first parameter of map() callback x is the value itself which will be undefined(because all the values in array are undefined).
i the second parameter will be the index of the element. Which will start from 0 upto 25.
String.fromCharCode is function which takes a character code(integer) and then convert it to string. For example character code for a is 97 so String.fromCharCode(97) will return "a". 98 for "b", 99 for "c" etc.
So after map() an array like ["a","b"....,"z"] will be generated.
-join() will convert that to string
Second Line:
str is given string. str.split('') will convert string to array. For example
if str is "abdc" it will return ["a","b","d","c"]
sort() is the array method which takes the callback. The two parameters are two values to be compared during sort(). a and b are two values.
charCodeAt acts in reverse as String.fromCharCode. For example "a".charCodeAt(0) will be return 97 for "b" it will 98 and so on.
a.charCodeAt(0) - b.charCodeAt(0) which is returned from sort() will sort array is ascending order. And join() will convert array to string.
So string "abdc" will become "abcd"
Third Line:
The third line is the main one. org is string "abcdefghijklmnopqrstuvwxyz". Now if any string is a substring of this string then it means its in alphabetical order. So we check the sorted str is includes in the string or not.
You can clean up the second line by
str = str.split('').sort().join('');
Because if no callback is passed to sort() it will sort in default order. Mean alphabetical order.

traverse a string char by char javascript

function SimpleSymbols(str) {
var letter =['a','b','c','d','e','f','g','h','i','j',
'k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
var newstr = "";
for (var i = 0; i<str.length; i++){
if (str.charAt(i).toLowerCase() in letter){
newstr += "M";
}
else{
newstr += "X";
}
}
return newstr;
}
If str is "Argument goes here" it returns XXXXXXXXX. WHy doesn't it return MMMMMMMMMM?
you do not look up an entry in an array with in. use indexOf() to find the position of an array entry. indexOf() will return the position or -1 if no entry is found.
for (var i = 0; i<str.length; i++){
var strChar = str.charAt(i).toLowerCase();
if ( letter.indexOf(strChar) >= 0 ) {
newstr += "M";
}
…
The in operator returns true if the object has a property with that name, not with that value.
An array is basically an object with numeric properties. I.e. the indexes are the property names of the object. It basically looks like this:
var letters = {
0: 'a',
1: 'b',
...
length: ...
};
So in your case the condition will only be true if str.charAt(i).toLowerCase() returns a number between 0 and letter.length (and since charAt only returns one character, it can only be 0-9).
Example:
> var letters = ['a', 'b', 'c'];
> 'a' in letters // array doesn't have a property 'a'
false
> 0 in letters // array has a property 0 (it's the first element)
true
So since, "Argument goes here" doesn't contain any digits, the in condition will always be false and that's why you get XXXXXX... as result.
See the question "How do I check if an array includes an object in JavaScript?" for testing the existence of an element in an array.
FWIW, to make the in operator work, you would have to create an object of the form:
var letters = {
'a': true,
'b': true,
// ...
};
but that's a bit cumbersome to write.
Allow me to offer a side view, another way handle what I think you intent to do by using Regular Expressions with something like:
"test2".replace(/[a-z]/gi,"M").replace(/[^M]/g,"X") //Outputs "MMMMX"
String.replace will replace an string that contains letters from [a-z] the i at the end of the expression means case insensitive. g means will search for all possible matches and not just the first match. In the second expression [^M] this ^ means negation so anything that is not an M will be replaced with X.
There is another way in which we implement a custom function within the String.replace using Regular Expressions and it can be implemented like this:
"test2".replace(/([a-z])|([^a-z])/gi,
function(m,g1, g2){
return g1 ? "M" : "X";
});
In regular expression parenthesis creates groups and | means or in this expression ([a-z])|([^a-z]) there 2 groups one with letters from a-z and the other which means everything that is not a-z with the replace function we asked only for group g1 if it is group 1 is M otherwise is an X.
Another cool thing you could do is add this function to all your string by prototyping it like:
String.prototype.traverse = function(){ return this.replace(/([a-z])|([^a-z])/gi,function(m,g1){ return g1 ? "M" : "X" });}
Then it can be used as simple as: "test1".traverse();

JavaScript split string by regex

I will have a string never long than 8 characters in length, e.g.:
// represented as array to demonstrate multiple examples
var strs = [
'11111111',
'1RBN4',
'12B5'
]
When ran through a function, I would like all digit characters to be summed to return a final string:
var strsAfterFunction = [
'8',
'1RBN4',
'3B5'
]
Where you can see all of the 8 single 1 characters in the first string end up as a single 8 character string, the second string remains unchanged as at no point are there adjacent digit characters and the third string changes as the 1 and 2 characters become a 3 and the rest of the string is unchanged.
I believe the best way to do this, in pseudo-code, would be:
1. split the array by regex to find multiple digit characters that are adjacent
2. if an item in the split array contains digits, add them together
3. join the split array items
What would be the .split regex to split by multiple adajcent digit characters, e.g.:
var str = '12RB1N1'
=> ['12', 'R', 'B', '1', 'N', '1']
EDIT:
question:
What about the string "999" should the result be "27", or "9"
If it was clear, always SUM the digits, 999 => 27, 234 => 9
You can do this for the whole transformation :
var results = strs.map(function(s){
return s.replace(/\d+/g, function(n){
return n.split('').reduce(function(s,i){ return +i+s }, 0)
})
});
For your strs array, it returns ["8", "1RBN4", "3B5"].
var results = string.match(/(\d+|\D+)/g);
Testing:
"aoueoe34243euouoe34432euooue34243".match(/(\d+|\D+)/g)
Returns
["aoueoe", "34243", "euouoe", "34432", "euooue", "34243"]
George... My answer was originally similar to dystroy's, but when I got home tonight and found your comment I couldn't pass up a challenge
:)
Here it is without regexp. fwiw it might be faster, it would be an interesting benchmark since the iterations are native.
function p(s){
var str = "", num = 0;
s.split("").forEach(function(v){
if(!isNaN(v)){
(num = (num||0) + +v);
} else if(num!==undefined){
(str += num + v,num = undefined);
} else {
str += v;
}
});
return str+(num||"");
};
// TESTING
console.log(p("345abc567"));
// 12abc18
console.log(p("35abc2134mb1234mnbmn-135"));
// 8abc10mb10mnbmn-9
console.log(p("1 d0n't kn0w wh#t 3153 t0 thr0w #t th15 th1n6"));
// 1d0n't0kn0w0wh#t12t0thr0w0#t0th6th1n6
// EXTRY CREDIT
function fn(s){
var a = p(s);
return a === s ? a : fn(a);
}
console.log(fn("9599999gh999999999999999h999999999999345"));
// 5gh9h3
and here is the Fiddle & a new Fiddle without overly clever ternary

New to javascript, how to write reverse iteration?

I'm currently taking an introduction CIS class at my university and one of the projects is javascript. It is split into two unrelated parts and I was able to do the second part but I'm stuck on the first one. My professor wants me to write an iteration that will display in a reverse order whatever name I write in the prompt screen. So if I write "John Smith" it will display "htims nhoj". The issue is that I have no idea how to write it.
<html>
<body>
<script>
var namIn = window.prompt("Enter name:" );
var namAr = namIn.split("");
var namArLen = namAr.length;
document.write(namAr + "<br /> Length: " + namArLen);
</script>
</body>
</html>
Strings in JavaScript have a function called split() which turn them in to Arrays. Arrays in JavaScript have a function called reverse() which reverse their order, and a function called join() which turn them back into Strings. You can combine these into:
"John Smith".split("").reverse().join("")
This returns:
"htimS nhoJ"
Also, and I don't know if this is a typo, but you can throw a toLowerCase() to get 100% of what your question is after:
"John Smith".split("").reverse().join("").toLowerCase()
returns:
"htims nhoj"
As for the question in your title, you can specify the direction of a for loop in the last argument like so:
var reversed = [];
var name = "John Smith".split("");
for(var i = name.length-1; i >= 0; i--) {
reversed.push(name[i]);
}
console.log(reversed.join(""));
Which will output:
"htimS nhoJ"
There's no need to split this string into an array. Just use the charAt() function and a simple for loop.
var name = window.prompt("Enter name:");
var reverse = "";
for (var i = name.length - 1; i >=0; i--) {
reverse += name.charAt(i);
}
console.log(reverse)
Instead of converting the string to an array first, you're just reading the characters out of the string directly.
You can accomplish this by iterating only half the number of characters.
DEMO: http://jsfiddle.net/vgG2P/
CODE:
var name = "Bob Dylan".split("");
// The counters will meet in the middle.
// --------------+----------------------
// first char last char | inc dec
// -------v-------------v-----------v----v----v
for(var i = 0, j = name.length-1; i < j; i++, j--) {
var temp = name[i]; // Store the `i` char
name[i] = name[j]; // Replace the `i` char with the `j` char
name[j] = temp; // Replace the `j` char with the `i` char we stored
}
console.log(name.join("")); "nalyD boB"
EXPLANATION:
What we did was split the characters into an Array, and maintain two counters, one that increments from the first character at 0, and the other that decrements from the last character at .length - 1. Then simply swap the characters.
The iteration continues while your incrementing counter is less than your decrementing counter. Since they will meet in the middle, you'll end up incrementing only half the total length.
We can also build the halves of the result without using an Array:
DEMO: http://jsfiddle.net/vgG2P/1/
var name = "Bob Dylan";
var start = "", end = ""
for(var i = 0, j = name.length-1; i < j; i++, j--) {
end = name.charAt(i) + end
start += name.charAt(j)
}
if (i === j)
start += name.charAt(i)
console.log(start + end); "nalyD boB"
I'm assuming that your professor would not be asking you how to reverse a string if he hasn't yet introduced you to the concept of arrays and loops. Basically, a string like John Smith is just an array of characters like this:
0123456789
John Smith
Again, thinking in the sense that a string is just an array of characters, you have have 10 characters that need to be reversed. So how do you go about doing this? Well, you basically need to take the last character h from the "array" you're given and make it the first character in a new "array" you're going to create. Here's an example:
var known = 'John Smith';
var reversed = ''; // I'm making an empty string aka character array
var last = known.length - 1 // This is the index of the last character
for (var i = 0; i < known.length; i++)
{
temp += known[last - i];
}
(You can see it working here)
So what's happening?
We're looping over known starting at 0 and ending at 9 (from the first character to the last)
During each iteration, i is incrementing from 0 - 9
last always has a value of 9
last - i will give us indexes in reverse order (9, 8, 7, ..., 0)
So, when i is 0, last - i is 9 and known[9] is "h"; repeat this process and you get the reversed string
Hopefully this helps explain a little better what's happening when you call reverse() on an array.
(1) A more straight forward way without built-in functions:
function reverse(str) {
let reversed_string = "";
for (let i = str.length - 1; i >= 0; i--) {
reversed_string += str[i];
}
return reversed_string;
}
(2) Using ES2015 'for' helper function:
function reverse(str) {
let reversed_string = "";
for (let character of str) {
reversed_string = character + reversed_string;
}
return reversed_string;
}
(3) Using ES6 syntax and ES5.1 reduce():
function reverse(str) {
return str.split('').reduce((reversed, char) => char + reversed, '');
}
// reduce takes in 2 arguments. (1) arrow function, and (2) empty string.
Chances are, for an interview, that you will not able to use the built-in functions, especially for "reverse()".

Categories

Resources