How to reverse initial string and save space order - javascript

How to reverse initial string and save space order more correctly than in my solution. I need to transfrom initial string, to do it reversed but keep the same order of spaces as initiall string
'some text with spaces' //=> "seca psht iwtx etemos"
function test(str, result = "") {
let res = str.split('').reverse().join('')
for (let i = 0; i < res.length; i++) {
if (str[i] === " ") {
result += ` ${res[i]}`
str[i + 1];
} else if (str[i] !== " " && res[i] === " ") {
result += ""
} else {
result += res[i];
}
}
return result
}
console.log(test('some text with spaces')) //=> "seca psht iwtx etemos"

function test(str) {
const letters = str.split(""); // make array so we can modify it
const spaceIndexes = letters.reduce((arr, letter, index) => {
if (letter === " ") arr.push(index);
return arr;
}, []);
const reversed = letters.filter(l => l !== ' ').reverse(); // reverse and delete spaces
spaceIndexes.forEach((index) => reversed.splice(index, 0, " ")); // insert spaces at previous places
return reversed.join(""); // return as a string
}

You could take a single loop without splitting and get the non space characters from the end and insert spaces if one is found at the actual length of the new string.
function test(str) {
let i = str.length,
s = '';
while (i--) {
if (str[i] === ' ') continue;
while (str[s.length] === ' ') s += ' ';
s += str[i];
}
return s;
}
console.log(test('some text with spaces'));

This will return all non-blank letters in a reverse order with all blanks at the positions of the original string:
function test(str) {
let i=-1,spaces=[];
while ((i=str.indexOf(' ',i+1))>-1) spaces.push(i); // find space positions
let res=str.replace(/ /g,'').split('').reverse(); // remove spaces and
// turn into array and reverse it
spaces.forEach(i=>res.splice(i,0,' ')) // put spaces back into array
return res.join(''); // turn array to string and return
}
let str="let us try this function.";
console.log(str);
console.log(test(str))

Not exactly sure if there is better solution than this. But the best I could think of for now
The algorithm is
Find out the space indexes in the given string
Reverse the same sting
Add the space as per indexes got above and replace any additional spaces in string
function test(str) {
const mapping = {};
const pattern = /\s+/g;
while (match = pattern.exec(str)) {
mapping[match.index] = true;
}
return str.split('').reverse().reduce((acc, cur, index) => {
if(mapping[index]) acc += ' ';
acc += cur.replace(pattern, '');
return acc;
}, '');
}
// seca psht iwtx etemos
console.log(test('some text with spaces'))

let theString = "some text with spaces";
let spaceArr = [] // we will store spaces position in this array
let pos = 0
let strArr = theString.split(" ")
for(let i=0; i<strArr.length-1; i++){
spaceArr.push(pos + strArr[i].length)
pos = pos+1 + strArr[i].length
}
// now lets remove spaces , reverse string, put back orignal spaces
let res = strArr.join("").split("").reverse().join("").split("")
spaceArr.forEach((item,index)=>{
res.splice(item,0," ")
})
console.log(res.join(""))

Related

Implement the .split method

I need to implement the .split method in my own way without using prebuilt functions. The method should receive a string divided into 2 sentences by a dot and divide them through a separator.
For example, there is this string:
'word wooord wooooooooord wooooooord. wooooooooord woooooord woooord wooooooooord', separator in this case: '. '
The result should be:
['word wooord wooooooooord wooooooord", "wooooooooord woooooord woooord wooooooooord']
I tried to implement it myself, the first problem I encountered is that the words from the string are added character by character to the new array. The second problem is that the output is still a string even though I declared an array earlier.
function split(str, splitter){
let arrSent = []
for (let i = 0; i < str.length; i++){
if (str[i] != splitter){
arrSent += str[i]
}
}
return arrSent
}
console.log(split('word wooord wooooooooord wooooooord. wooooooooord woooooord woooord wooooooooord', '. '))
Since the delimiter can have more than one character, you need a system to upfront collect a sample of characters (of the same length as the delimiter) to be then compared with the delimiter:
const split = (str, delimiter) => {
// If delimiter is empty string just return an array of characters
if (delimiter === "") return [...str];
const len = delimiter.length;
const iter = str.length - len + 1; // max needed iterations
const arr = [""]; // Prefill it with empty string
let idx = 0; // arr insertion pointer
for (let i = 0; i < iter; i++) {
// Collect len chars from str as a sample
// to compare with the delimiter:
let sample = "";
for (let x = i; x < i + len; x++) {
sample += str[x];
}
const isSplit = sample === delimiter;
const isEnded = i === iter - 1;
if (isSplit) {
i += len - 1; // Consume splitted characters
idx += 1; // Increment arr pointer
arr[idx] = ""; // Prepare the new array key as empty string
} else {
// If loop ended append the entire sample.
// Otherwise, append a single character:
arr[idx] += isEnded ? sample : str[i];
}
}
return arr
}
console.log(split("word. etc", ". "));
console.log(split("word. etc. ", ". "));
console.log(split(". word yep. . etc. ", ". "));
console.log(split("word", ". "));
console.log(split("word", "word"));
console.log(split("word", ""));
console.log(split("", ""));
above, idx (starting at 0) is used as the output's arr insertion pointer. The idx is incremented if the sample matches the delimiter. Also, if there's a match, we need to skip iterations i += len, to not include the delimiter in the output array.
To test, create many examples and right before return arr; use console.log(JSON.stringify(arr) === JSON.stringify(str.split(delimiter))); - it should return true for all the submitted tests.

Writing function that returns string but with all five or more letters reversed JS

first time posting. I'm writing a function in js that reverses words with more than 5 characters in a given string. It works, but I think it is adding extra "space" strings that it doesn't need if the string inputted is only one word. I know I have too many variables and there is a way better way to do this. I'm pretty new to this, but anything helps. Thanks!
const exString = "Hey fellow warriors"
function spinWords(string){
let newWord = string.split(' ');
let fiveWord = "";
let lessWord = "";
for(i=0; i<newWord.length;i++){
if(newWord[i].length >=5){
fiveWord += newWord[i].split('').reverse() + ' ';
}
else{
lessWord += newWord[i]
}
}
newFiveWord = fiveWord.replace(/,/g,'');
return lessWord + ' ' + newFiveWord
}
console.log(spinWords(exString));
const spinWords = str => str
.split(' ')
.map(word => word.length >= 5
? [...word].reverse().join('')
: word)
.join(' ')
console.log(spinWords("Hey fellow warriors"))
Turn the string into an array of words
Modify each word. If 5+ letters: [..word] turns the string into an array of letters ('hi' > ['h', 'i']). Then reverse the array, and turn the letters back into one string.
Undo step one by turning the array into one string.
function reversedText() {
let text = prompt("Enter text");
const words = text?.split(" ");
const newText = words.map((word) => {
if (word.length >= 5) {
return (word.split("").reverse().join(""));
}
return word;
});
if (newText.length > 0) {
return newText.filter(notNull).join(" ");
} else {
return 'Your sentence have words which have length less than 5';
}
}
function notNull(value) {
return value != null
}
console.log(reversedText());

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 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,

print like this * "a" -> "a1" * "aabbbaa" -> "a2b3a2"

I am new to js.
can you tell me how to print like this * "a" -> "a1" * "aabbbaa" -> "a2b3a2"
i tried with hash map but test cases failing.
providing my code below.
i am not good in hash map.
can you tell me how to solve with hash map so that in future I can fix it my self.
not sure what data structure to use for this one.
providing my code below.
const _ = require("underscore");
const rle = ( input ) => {
console.log("input--->" + input);
//var someString ="aaa";
var someString = input;
var arr = someString.split("");
var numberCount = {};
for(var i=0; i< arr.length; i++) {
var alphabet = arr[i];
if(numberCount[alphabet]){
numberCount[alphabet] = numberCount[alphabet] + 1;
}
else{
numberCount[alphabet] = 1;
}
}
console.log("a:" + numberCount['a'], "b:" + numberCount['b']);
}
/**
* boolean doTestsPass()
* Returns true if all the tests pass. Otherwise returns false.
*/
/**
* Returns true if all tests pass; otherwise, returns false.
*/
const doTestsPass = () => {
const VALID_COMBOS = {"aaa": "a3", "aaabbc":"a3b2c1"};
let testPassed = true;
_.forEach(VALID_COMBOS, function(value, key) {
console.log(key, rle(key));
if (value !== rle(key)) {
testPassed = false;
}
});
return testPassed;
}
/**
* Main execution entry.
*/
if(doTestsPass())
{
console.log("All tests pass!");
}
else
{
console.log("There are test failures.");
}
You could
match groups of characters,
get the character and the count and
join it to a string.
function runLengthEncoding(string) {
return string
.match(/(.)\1*/g) // keep same characters in a single string
.map(s => s[0] + s.length) // take first character of string and length
.join(''); // create string of array
}
console.log(['a', 'aaa', 'aaabbc'].map(runLengthEncoding));
This is a bit more understandable version which iterates the given string and count the characters. If a different character is found, the last character and count is added to the result string.
At the end, a check is made, to prevent counting of empty strings and the last character cound is added to the result.
function runLengthEncoding(string) {
var result = '',
i,
count = 0,
character = string[0];
for (i = 0; i < string.length; i++) {
if (character === string[i]) {
count++;
continue;
}
result += character + count;
character = string[i];
count = 1;
}
if (count) {
result += character + count;
}
return result;
}
console.log(['', 'a', 'aaa', 'aaabbc'].map(runLengthEncoding));
You can reduce the array into a multidimensional array. map and join the array to convert to string.
const rle = (input) => {
return input.split("").reduce((c, v) => {
if (c[c.length - 1] && c[c.length - 1][0] === v) c[c.length - 1][1]++;
else c.push([v, 1]);
return c;
}, []).map(o => o.join('')).join('');
}
console.log(rle("a"));
console.log(rle("aabbbaa"));
console.log(rle("aaaaaa"));
Your function rle doesn't return a result.
Also note, this implementation may pass the test cases you wrote, but not the examples you mentioned in your question: for the string "aabbaa" this will produce "a4b2", not " a2b2a2" .
A simpler solution:
function runLengthEncoding(str) {
let out = "";
for (let i = 0; i < str.length; ++i) {
let temp = str[i];
let count = 1;
while (i < str.length && str[i+1] == temp) {
++count;
++i;
}
out += temp + count;
} // end-for
return out;
}
console.log(runLengthEncoding("a"));
console.log(runLengthEncoding("aabbbaa"));
console.log(runLengthEncoding("aaaaaa"));

Categories

Resources