Getting Name initials using JS - javascript

I would like to extract initials from a string, like:
Name = FirstName LastName
Initials = FL
I can get the above result using this,
const initials = item
.FirstName
.charAt(0)
.toUpperCase() +
item
.LastName
.charAt(0)
.toUpperCase();
But now my requirements are changed as if name only consist of 1 word or more then 2, so in following cases how can I get initials as per my requirements,
FullName = FU
FirstName MiddleName LastName = FL
1stName 2ndName 3rdName 4thName 5thName = 15
How can I get above initials from a string in JS?
Also now I only have item.Name string as an input

Why no love for regex?
Updated to support unicode characters and use ES6 features
let name = 'ÇFoo Bar 1Name too ÉLong';
let rgx = new RegExp(/(\p{L}{1})\p{L}+/, 'gu');
let initials = [...name.matchAll(rgx)] || [];
initials = (
(initials.shift()?.[1] || '') + (initials.pop()?.[1] || '')
).toUpperCase();
console.log(initials);

You can use this shorthand js
"FirstName LastName".split(" ").map((n)=>n[0]).join(".");
To get only First name and Last name you can use this shorthand function
(fullname=>fullname.map((n, i)=>(i==0||i==fullname.length-1)&&n[0]).filter(n=>n).join(""))
("FirstName MiddleName OtherName LastName".split(" "));

Check the getInitials function below:
var getInitials = function (string) {
var names = string.split(' '),
initials = names[0].substring(0, 1).toUpperCase();
if (names.length > 1) {
initials += names[names.length - 1].substring(0, 1).toUpperCase();
}
return initials;
};
console.log(getInitials('FirstName LastName'));
console.log(getInitials('FirstName MiddleName LastName'));
console.log(getInitials('1stName 2ndName 3rdName 4thName 5thName'));
The functions split the input string by spaces:
names = string.split(' '),
Then get the first name, and get the first letter:
initials = names[0].substring(0, 1).toUpperCase();
If there are more then one name, it takes the first letter of the last name (the one in position names.length - 1):
if (names.length > 1) {
initials += names[names.length - 1].substring(0, 1).toUpperCase();
}

Get First and Last Initial: John Doe Smith => JS
name.match(/(\b\S)?/g).join("").match(/(^\S|\S$)?/g).join("").toUpperCase()
Get All Initials: "John Doe Smith" => "JDS"
name.match(/(\b\S)?/g).join("").toUpperCase()
Get First and Last except get First 2 in case there is only first. (OP's question)
John => JO and "John Doe Smith" => "JS"
name.match(/(^\S\S?|\b\S)?/g).join("").match(/(^\S|\S$)?/g).join("").toUpperCase()
International Version: "Störfried Würgekloß" => "SW"
name.match(/(^\S\S?|\s\S)?/g).map(v=>v.trim()).join("").match(/(^\S|\S$)?/g).join("").toLocaleUpperCase()
Note: If the name contains , or other non word characters, you might use /w instead of /S or sanitize it beforehand

Common Avatar Use-case
Just surprised that none of the answers put Array.reduce() to good use.
const getInitials = (fullName) => {
const allNames = fullName.trim().split(' ');
const initials = allNames.reduce((acc, curr, index) => {
if(index === 0 || index === allNames.length - 1){
acc = `${acc}${curr.charAt(0).toUpperCase()}`;
}
return acc;
}, '');
return initials;
}
Run the snippet below to check the initials for different use cases -
const testNames = [
'Albus Percival Wulfric Brian dumbledore', // AD
'Harry Potter', // HP
'Ron', // R
'', // <empty>
'Çigkofte With Érnie', // ÇÉ
'Hermione ', // H (Notice that there is a space after the name)
'Neville LongBottom ' // NL (space after name is trimmed)
]
const getInitials = (fullName) => {
const allNames = fullName.trim().split(' ');
const initials = allNames.reduce((acc, curr, index) => {
if(index === 0 || index === allNames.length - 1){
acc = `${acc}${curr.charAt(0).toUpperCase()}`;
}
return acc;
}, '');
return initials;
}
console.log(testNames.map(getInitials));
Note
This one is for a widely used case for displaying names in Avatars, where you wouldn't want first name initial to be repeated twice and want to restrict the initials to a max of 2 letters

You can use below one line logic:
"FirstName MiddleName LastName".split(" ").map((n,i,a)=> i === 0 || i+1 === a.length ? n[0] : null).join("");

There are some other answers which solve your query but are slightly complicated. Here's a more readable solution which covers most edge cases.
As your full name can have any number of words(middle names) in it, our best bet is to spit it into an array and get the initial characters from the first and last words in that array and return the letters together.
Also if your 'fullName' contains only one word, word at array[0] and array[array.length - 1] would be the same word, so we are handling that if the first if.
function nameToInitials(fullName) {
const namesArray = fullName.trim().split(' ');
if (namesArray.length === 1) return `${namesArray[0].charAt(0)}`;
else return `${namesArray[0].charAt(0)}${namesArray[namesArray.length - 1].charAt(0)}`;
}
Sample outputs :
> nameToInitials('Prince') // "P"
> nameToInitials('FirstName LastName') // "FL"
> nameToInitials('1stName 2ndName 3rdName 4thName 5thName')
// "15"

'Aniket Kumar Agrawal'.split(' ').map(x => x.charAt(0)).join('').substr(0, 2).toUpperCase()

let initial = username.match(/\b(\w)/g).join('')

You can do a function for that:
var name = 'Name';
function getInitials( name,delimeter ) {
if( name ) {
var array = name.split( delimeter );
switch ( array.length ) {
case 1:
return array[0].charAt(0).toUpperCase();
break;
default:
return array[0].charAt(0).toUpperCase() + array[ array.length -1 ].charAt(0).toUpperCase();
}
}
return false;
}
Fiddle: http://jsfiddle.net/5v3n2f95/1/

const getInitials = name => name
.replace(/[^A-Za-z0-9À-ÿ ]/ig, '') // taking care of accented characters as well
.replace(/ +/ig, ' ') // replace multiple spaces to one
.split(/ /) // break the name into parts
.reduce((acc, item) => acc + item[0], '') // assemble an abbreviation from the parts
.concat(name.substr(1)) // what if the name consist only one part
.concat(name) // what if the name is only one character
.substr(0, 2) // get the first two characters an initials
.toUpperCase(); // uppercase, but you can format it with CSS as well
console.log(getInitials('A'));
console.log(getInitials('Abcd'));
console.log(getInitials('Abcd Efgh'));
console.log(getInitials('Abcd Efgh Ijkl'));
console.log(getInitials('Abcd Efgh Ijkl Mnop'));
console.log(getInitials('Ábcd Éfgh Ijkl Mnop'));
console.log(getInitials('Ábcd - Éfgh Ijkl Mnop'));
console.log(getInitials('Ábcd / # . - , Éfgh Ijkl Mnop'));

+ efficient
+ no loops
+ simplified branching (ternary operator only)
+ handles no-space cases (prints 2 chars)
+ no array memory allocation (actually no array processing)
- requires trimmed string input
function getInitials(name) {
const hasTokens = name.indexOf(' ') !== -1
return name.substring(0, hasTokens ? 1 : 2) + (hasTokens ? name.charAt(name.lastIndexOf(' ') + 1) : '')
}
console.log(getInitials("A B"), 'AB')
console.log(getInitials("Abc Def"), 'AD')
console.log(getInitials("Abc Xyz"), 'AX')
console.log(getInitials("S Xyz"), 'SX')
console.log(getInitials("SXyz "), 'SX')
console.log(getInitials("T30"), 'T3')

Easier with map function:
var name = "First Last";
var initials = Array.prototype.map.call(name.split(" "), function(x){ return x.substring(0,1).toUpperCase();}).join('');

Similar but slightly neater version of #njmwas answer:
let name = 'Fred Smith';
let initials = name.split(' ').reduce((acc, subname) =>
acc + subname[0], '')
console.log(initials) // FS
Or, to include the abbreviation dots:
let name = 'Fred Smith';
let initials = name.split(' ').reduce((acc, subname) =>
acc + subname[0] + '.', '')
console.log(initials) // F.S.

This solution uses Array capabilities, Arrow function and ternary operator to achieve the goal in one line.
If name is single word, just take first two chars, but if more, then take 1st chars of first and last names.
(thanks omn for reminding single word name use case)
string.trim().split(' ').reduce((acc, cur, idx, arr) => acc + (arr.length > 1 ? (idx == 0 || idx == arr.length - 1 ? cur.substring(0, 1) : '') : cur.substring(0, 2)), '').toUpperCase()

To get the first name and last name initials, try using the function below.
const getInitials = string => {
const names = string.split(' ');
const initials = names.map(name => name.charAt(0).toUpperCase())
if (initials.length > 1) {
return `${initials[0]}${initials[initials.length - 1]}`;
} else {
return initials[0];
}
};
console.log(getInitials("1stName 2ndName 3rdName 4thName 5thName")); // 15
console.log(getInitials("FirstName MiddleName LastName")); // FL
WHAT HAPPENED: The function splits the incoming string, ignores any name between the first & last names and returns their initials. In the case a single name is entered, a single initial is returned. I hope this helps, cheers.

I needed this today to act as method in my React code. I was getting the user name from the state as props. After that I just passed my method inside my component's props.
getUserInitials() {
const fullName = this.props.user.name.split(' ');
const initials = fullName.shift().charAt(0) + fullName.pop().charAt(0);
return initials.toUpperCase();
}

function getInitials(name) {
return (
name
.match(/(?<=\s|^)\p{L}\p{Mn}*/gu)
?.filter((el, i, array) => i === 0 || i === array.length - 1)
.join("") || ""
);
}
console.log(getInitials('ÇFoo Bar 1Name too ÉLong'));
console.log(getInitials('Q̈lice Hwerty')); // Q is followed by U+0308 (Combining Diaeresis)
console.log(getInitials('A Foo'));
console.log(getInitials('Bob'));
Safari doesn't yet support lookbehinds in regexes (see caniuse), so if Safari support is needed, it can be rewritten this way:
function getInitials(name) {
return (
name
.match(/(\s|^)\p{L}\p{Mn}*/gu)
?.filter((el, i, array) => i === 0 || i === array.length - 1)
.map(el => el.trimStart())
.join("") || ""
);
}

const getInitials = name => {
let initials = '';
name.split(' ').map( subName => initials = initials + subName[0]);
return initials;
};

You can do something like this;
function initials(name){
//splits words to array
var nameArray = name.split(" ");
var initials = '';
//if it's a single word, return 1st and 2nd character
if(nameArray.length === 1) {
return nameArray[0].charAt(0) + "" +nameArray[0].charAt(1);
}else{
initials = nameArray[0].charAt(0);
}
//else it's more than one, concat the initials in a loop
//we've gotten the first word, get the initial of the last word
//first word
for (i = (nameArray.length - 1); i < nameArray.length; i++){
initials += nameArray[i].charAt(0);
}
//return capitalized initials
return initials.toUpperCase();
}
You can then use the function like so;
var fullname = 'badmos tobi';
initials(fullname); //returns BT
var surname = 'badmos';
initials(surname); //returns BA
var more = 'badmos gbenga mike wale';
initials(more); //returns BW;
I hope this helps.

var personName = "FirstName MiddleName LastName";
var userArray = personName.split(" ");
var initials = [];
if(userArray.length == 1){
initials.push(userArray[0][0].toUpperCase() + userArray[0][1]).toUpperCase();}
else if(userArray.length > 1){
initials.push(userArray[0][0].toUpperCase() + userArray[userArray.length-1][0].toUpperCase());}
console.log(initials);

This should work for majority of the cases including middle names and first name only (extension on #njmwas answer).
const initialArr = name.split(" ").map((n)=>n[0]);
const init = (initialArr.length > 1)? `${initialArr[0]}${initialArr[initialArr.length - 1]}` : initialArr[0];
const initials = init.toUpperCase();

Easy way using ES6 Destructering:
const getInitials = string =>
string
.split(' ')
.map(([firstLetter]) => firstLetter)
.filter((_, index, array) => index === 0 || index === array.length - 1)
.join('')
.toUpperCase();

THIS IS THE SIMPLE UTILITY METHOD THAT HELPS TO GET THE INITIALS OF THE NAME
BY SIMPLY PASSING THE NAME TO getInitials function
// eg getInitials("harry potter") ==> "HP"
const getInitials = (name) => {
var parts = name.split(' ')
var initials = ''
for (var i = 0; i < parts.length; i++) {
if (parts[i].length > 0 && parts[i] !== '') {
initials += parts[i][0]
}
}
return initials.toUpperCase();
}

Something more functional: D
const getInitials = (string) => {
const [firstname, lastname] = string.toUpperCase().split(' ');
const initials = firstname.substring(0, 1);
return lastname
? initials.concat(lastname.substring(0, 1))
: initials.concat(firstname.substring(1, 2));
};
console.log(getInitials('FirstName LastName')); // FL
console.log(getInitials('FirstName MiddleName LastName')); // FM
console.log(getInitials('FirstName')); // FI

var getInitials = function (string) {
var names = string.split(' '),
initials = names[0].substring(0, 1).toUpperCase()+'.';
if (names.length > 1) {
initials += names[names.length - 2].substring(0, 1).toUpperCase()+'.';
}
return initials=initials+names[names.length - 1].toUpperCase();
}
console.log(getInitials('Rama Krishna Narayan'));
var getInitials = function (string) {
var names = string.split(' '),
initials = names[0].substring(0, 1).toUpperCase()+'.';
if (names.length > 1) {
initials += names[names.length - 2].substring(0, 1).toUpperCase()+'.';
}
return initials=initials+names[names.length - 1].toUpperCase();
}
console.log(getInitials('Rama Krishna Narayan'));

A better way.
nameToInitials(name: string): string {
const portions = name.split(' ')
.map(val => val[0]);
return portions.slice(0, 2)
.reduce((a, b) => a + b, '').toUpperCase();
}

I am sorry if I misunderstand something, but most answers are so.... complicated.
My solution is (for international, actually hungarian names):
var regex = /[A-ZÍÉÁŰŐÚÖÜÓ]{1}/g
var monogram = 'Üveges Tóth Ödön'.match(regex).join('')

just updated Andrea's version:
var getInitials = function (string) {
var initials = "";
var names = string.split(' ');
for (n = 0; n < names.length; n++) {
initials += names[n].substring(0, 1).toUpperCase();
}
return initials;
};
if string includes LastName, just change names.length to names.length-1 to ignore lastname

Using some es6 functionality:
const testNameString = 'Hello World';
const testNameStringWeird = 'Hello darkness My - Óld Friend Nikolaus Koster-Walder ';
const getInitials = nameString =>{
const regexChar = /\D\w+/
return nameString
.trim() //remove trailing spaces
.split(' ') // splits on spaces
.filter(word => word.length > 0) // strip out double spaces
.filter(word => regexChar.test(word)) // strip out special characters
.map(word => word.substring(0, 1).toUpperCase()) // take first letter from each word and put into array
}
console.log('name:',testNameString,'\n initials:',getInitials(testNameString));
console.log('name:',testNameStringWeird,'\n initials:',getInitials(testNameStringWeird));

Related

Double for loop in Javascript inner array length

I am trying to create a function that takes in a string and changes each letters value to a "(" if the character is not duplicated in the string, and a ")" if the character does have a duplicate present in the string. I have decided to go an unconventional route to solve this problem but I am running in to an issue with a double for loop. From what I understand, the inner for loop in javascript does not have access to the variables outside of the loop. I want to loop through every item in an array twice but I'm not sure what to set the inner loops length as.
Here is my code:
function sortAndChange(word) {
const splitter = word.toLowerCase().split("");
//let jSplitter = word.toLowerCase().split("").length;
let endResult = "";
let truthArray = [];
for(i = 0; i < splitter.length; i++){
for(j = 0; j < splitter.length; j++){
console.log(j);
if(splitter[i] == splitter[j]){
truthArray.push(true);
} else {
truthArray.push(false);
}
}
console.log(truthArray);
truthArray.every(item => item === false) ? endResult += "(" : endResult += ")";
truthArray = [];
}
console.log(endResult);
}
Expected Result:
sortAndChange("Success") //expected output: ")())())"
sortAndChange("easy") //expected output: "(((("
You can do that in following steps:
Convert string to array using split and use map() on it.
Compare the indexOf() and lastIndexOf() to check if its duplicate or not.
Return the ) or ( based on ur condition. And then at last join the array
function sortAndChange(str){
let arr = str.toLowerCase().split('')
return arr.map(x => {
//if its not duplicated
if(arr.indexOf(x) === arr.lastIndexOf(x)){
return '('
}
//If its duplicated
else{
return ')'
}
}).join('');
}
console.log(sortAndChange("Success")) //expected output: ")())())"
console.log(sortAndChange("easy")) //expected output: "(((("
You could take a object and keep a boolean value for later mapping the values.
This approach has two loops with O(2n)
function sortAndChange(word) {
word = word.toLowerCase();
var map = [...word].reduce((m, c) => (m[c] = c in m, m), {});
return Array
.from(word, c => '()'[+map[c]])
.join('');
}
console.log(sortAndChange("Success")); // )())())
console.log(sortAndChange("easy")); // ((((
This can easily be achieved using a combination of regex and the map construct in javascript:
const input = "this is a test";
const characters = input.toLowerCase().split('');
const transformed = characters.map(currentCharacter => {
const regexpression = new RegExp(currentCharacter, "g");
if (input.toLowerCase().match(regexpression || []).length > 1) return ')'
return '(';
}).join("");
console.log(transformed);
Look at the following snippet and comments
function sortAndChange(str) {
// we create an array containing the characters on the string
// so we can use Array.reduce
return str.split('').reduce((tmp, x, xi) => {
// we look if the character is duplicate in the string
// by looking for instance of the character
if (str.slice(xi + 1).includes(x.toLowerCase())) {
// Duplicate - we replace every occurence of the character
tmp = tmp.replace(new RegExp(x, 'gi'), ')');
} else {
// Not duplicate
tmp = tmp.replace(new RegExp(x, 'gi'), '(');
}
return tmp;
}, str);
}
console.log(sortAndChange('Success')); //expected output: ")())())"
console.log(sortAndChange('Easy')); //expected output: "(((("
1) use Array.from to convert to array of chars
2) use reduce to build object with key-value pairs as char in string and ( or ) as value based on repetition .
3) Now convert original string to result string using the chars from above object.
function sortAndChange(str) {
const str_arr = Array.from(str.toLowerCase());
const obj = str_arr.reduce(
(acc, char) => ((acc[char] = char in acc ? ")" : "("), acc),
{}
);
return str_arr.reduce((acc, char) => `${acc}${obj[char]}`, "");
}
console.log(sortAndChange("Success")); // ")())())"
console.log(sortAndChange("easy")); // ((((

Replace consecutive white spaces between words with one hyphen

The question is from freecodecamp Link
Fill in the urlSlug function so it converts a string title and returns the hyphenated version for the URL. You can use any of the methods covered in this section, and don't use replace. Here are the requirements:
The input is a string with spaces and title-cased words
The output is a string with the spaces between words replaced by a
hyphen (-)
The output should be all lower-cased letters
The output should not have any spaces
// the global variable
var globalTitle = " Winter Is Coming";
function urlSlug(title) {
let toArr = title.split("");
let newArr = toArr.map(a=> {
if(a==" "){
a= "-";
}
return a.toLowerCase();
} );
if(newArr[0] == "-"){
newArr.splice(0,1);
}
let finalArr = newArr.join("");
return finalArr;
}
// Add your code above this line
var winterComing = urlSlug(globalTitle); // Should be "winter-is-coming"
console.log(urlSlug(globalTitle));
Right now I have not been able to solve how I could get rid of the extra hyphen from the output.
I'm not supposed to use replace.
You could do this easily using trim() and a simple regex:
var globalTitle = " Winter Is Coming Now ";
var slug = globalTitle.trim().replace(/[ ]+/g, '-').toLowerCase();
console.log(slug);
[ ]+ ensures that any number of spaces (1 or more) gets replaced with a minus sign once.
If for some reason you can't use replace, you could use Array.filter() like so:
var title = " Winter Is Coming Now ";
var slug = title.split(" ").filter(word => word.length > 0).join("-").toLowerCase();
console.log(slug);
I was working on it till now , Haven't looked at the answers.
But I solved it this way. Might be inefficient.
// the global variable
var globalTitle = "Winter Is Coming";
function urlSlug(title) {
let toArr = title.split("");
let newArr = toArr.map(a=> {
if(a==" "){
a= "-";
}
return a.toLowerCase();
} );
if(newArr[0] == "-"){
newArr.splice(0,1);
}
for(let i=0;i<newArr.length;i++){
if(newArr[i-1]=="-"&& newArr[i]=="-")
{
newArr.splice(i,1,"");
}
}
let finalArr = newArr.join("");
return finalArr;
}
var winterComing = urlSlug(globalTitle); // Should be "winter-is-coming"
console.log(urlSlug(globalTitle));
Another option would be to continue your thought of split() and then use reduce to reduce the elements of the array to a single output:
var globalTitle = " Winter Is Coming";
function urlSlug(title) {
let split = title.split(' ');
return split.reduce((accumulator, currentValue, index) => {
if (currentValue.length > 0) {
accumulator += currentValue.toLowerCase();
accumulator += (index < split.length - 1) ? '-' : '';
}
return accumulator;
});
}
console.log(urlSlug(globalTitle));

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.

How to correctly use Array.map() for replacing string with alphabet position

Other SO 'Replace string with alphabet positions' questions didn't utilize map, which is what I'm trying to learn how to use to solve this.
Problem:
Given a string, replace every letter with its position in the alphabet.
If anything in the text isn't a letter, ignore it and don't return it.
"a" = 1, "b" = 2, etc.
What I've tried is:
-looping over a new array instance and setting the index value to String.fromCharCode()
- taking input string making it lowercase
-splitting to array
-return array.map().join(' ')
function alphabetPosition(text) {
let alphabet = new Array(26);
for (let i = 0; i<26; ++i) {
let char = String.fromCharCode(97 + i);
alphabet[i] = char;
}
text = text.toLowerCase();
let arr = text.split('');
return arr.map(element => { return element = alphabet.indexOf(element+1) }).join(' ');
}
expected it to return a string of alphabet positions, but got nothing at all. What is wrong with my implementation of Array.map()?
In your map element would be a letter, "a" for example. Then you add (concat) 1 to it, which results in "a1" which is not in your alphabet. Also element = is unneccessary, returning the position is enough.
You've complicated the solution, the simplest approach would be to just find the charcode and return that.
function alphabetPosition(text) {
let str = '';
for (var i = 0; i < text.length; i++) {
str += (text[i] + (text.charCodeAt(i) - 96));
}
return str;
}
I totally understand that is a coding challenge, interview question or likewise so if you really need to use map() you should only return the result of the callback passed to map as follows :
return arr.map(x => alphabet.indexOf(x) + 1).join(' ')
However reduce() seems more appropriate in your case :
return arr.reduce((ac, cv) => ac + (alphabet.indexOf(cv) + 1) + ' ', '')
Your map() last line of the function was returning the value of
an assignment.
return arr.map(element => { return element = alphabet.indexOf(element+1) }).join(' ');
Just alphabet.indexOf(element) would have sufficed.
This will give you the result you want:
alphabetPosition = text => {
let alphabet = new Array(26);
for (let i = 0; i < 26; ++i) {
let char = String.fromCharCode(97 + i);
alphabet[i] = char;
}
return text.toLowerCase().split('').map(element =>
alphabet.indexOf(element)
).join(' ');
}
console.log(alphabetPosition("This is a string"));
Hope this helps,

Return a string with swapping every element[0] by element[1] in a string

I want to swap element 0 by element 1 so element 1 become 0 idx and element 0 become 1 idx.
for instance Hello guys becomes eHllo ugys
my code is kind of tedious and it returns something like this eHll ougys it moves the last letter of a word to the first letter of the next word.
is there a way to do it without forloop?.
const tex = `Hello guys`;
const swap = str => {
let swapped = [];
strin = str.split('');
for (let i = 0; i < strin.length; i++) {
if (i < strin.length) {
swapped[i] = strin[i + 1];
swapped[i + 1] = strin[i];
i += 1;
} else {
swapped[i] = strin[i];
}
}
return swapped.join('');
}
console.log(swap(tex));
One option is to use a regular expression - capture one word character at the beginning of a word followed by another captured word character, and replace with those swapped capture groups:
const tex = `Hello guys`;
const Swap = str => str.replace(/\b(\w)(\w)/g, '$2$1');
console.log(Swap(tex));
This alternative splits the string by space.
Then, using the array, the function map converts the strings into the desired output.
let swap = s =>
s.split(/\s/).map(s => {
let split = s.split(''),
letters = [];
if (split.length > 1) { // This is for string with only one char
// Get the two chars -> He
// reverse them -> eH
letters = split.splice(0, 2).reverse();
}
return letters.join('') + split.join('');
}).join(' ');
console.log(swap("Hello guys"));
console.log(swap("Ele From S"));
You can also do it using split and join (without any regex):
const tex = `Hello guys`;
const strs = tex.split(' ')
const changed = strs.map(str => {
const s = str.split('')
const s1 = s[1]
const s0 = s[0]
s[0] = s1
s[1] = s0
return s.join('')
})
console.log(changed.join(' '))

Categories

Resources