I have a string containing numbers and different mathematical operators. How can I parse this string from var str = "123+45-34"; an convert it to an array
var arr = [123, '+', 45, '-',34];
One approach would be to split the string using a regex and then convert the parts into numbers where possible:
var str = "123+45-34";
var matches = str.match(/(\d+|\+|-|\/|\*)/g);
console.log(matches); // ["123", "+", "45", "-", "34"]
var asNumbers = matches.map(function(match) {
return +match || match
})
console.log(asNumbers); // [123, "+", 45, "-", 34]
It looks like you want to split your string on word boundaries:
var str = "123+45-34";
console.log(str.split(/\b/));
You could use a different approach with an operator object, which could be usefull for calculating the value later.
function split(s) {
var a = s.split(''),
i = 1;
while (i < a.length) {
if (!(a[i - 1] in operators || a[i] in operators)) {
a[i - 1] += a.splice(i, 1)[0];
continue;
}
i++;
}
return a.map(function (b) {
return b in operators ? b : +b;
});
}
var operators = { '+': true, '-': true },
str = "123+45-34+1e13";
console.log(split(str));
This code tries to traverse through the string.Each charecter is appended into a newstring,until + or - is found,once they are found string formed till now will be pushed into newarray and special charecter either + or - is also pushed into newarray and again this process continues till the end of the string
Ex:123+
it traverses the string.
first my newString ="1" ,then newString="12" finally newString="123"
as soon as + is found ,it pushes newString into newarray.now newArray is ["123" ] and '+' should also be pushed ,now array becomes ["123","+"].this process continues
Here i have taken into consideration of special charecters as only + and -
var str="123+45-34";
var newarr=[];
var newStr="";
for(var index=0;index<str.length;index++){
if(str[index]!='+'&& str[index]!='-')
newStr+=str[index];
else{
newarr.push(newStr);
newarr.push(str[index]);
newStr="";
}
}
console.log(newarr);
Hope this helps
Related
I have a scenario where I need to reverse a substring inside a string. The Javascript string is immutable and the traditional swapping technique on a string is not working here. So I have decided to use the string.split('') and string.join('') methods to get the solution. Please check the code below.
function reverseAString(str, startIndex, endIndex) {
let left = startIndex;
let right = endIndex;
let output = str;
while(left < right) {
const arr = output.split('');
let temp = arr[left]
arr[left] = arr[right]
arr[right] = temp;
output = arr.join('');
left += 1;
right -= 1;
}
return output
}
This is working as expected. But is there any better way to reverse the substring as the above solution is not the best way to achive reversal?
here is your function but simplify. we can chain calling string method into array method. Array.prototype.reverse() is used to reverse an array and Array.prototype.join() is used concatenate all the element(s) in an array into a string. String.prototype.substring() is used to cut string out of the original string but does not alter/change the original string.
function reverseASubstring(str, startIndex, endIndex) {
let reversedStr = str.substring(startIndex, endIndex).split("").reverse().join("");
return str.substring(0, startIndex) + reversedStr + str.substring(endIndex);
}
console.log(reverseASubstring("Tony is Tony in reverse.", 0, 4));
This solution builds a regex with two capture groups, one for number of characters to skip (e.g. start index), and one for the number of chars to reverse. With this you can apply a single regex replace that reverses the second capture group using .split('').reverse().join('')
function reverseASubstring(str, start, end) {
let regex = new RegExp('^(.{' + start + '})(.{' + (end - start + 1) + '})');
return str.replace(regex, (m, c1, c2) => c1 + c2.split('').reverse().join(''));
}
let str = 'Hello world.';
console.log(str, 0, 4, '=>', reverseASubstring(str, 0, 4));
console.log(str, 6, 10, '=>', reverseASubstring(str, 6, 10));
Sorry if the title sounds confusing. Basically what I am trying to do is to split a decimal number like this 0.1000 into two part - 1. 0.1 and 000 so I can render them differently with different styles.
Check out this screenshot
All the numbers are represented in strings. The tricky part is that we cannot split the number using number.split('0') since we only want to split at the first zero that appears after a non-zero integer.
Not sure how I can do this.
If I did not misunderstand what you are trying to achieve, you can do it with a regex that only matches unlimited zeros that are at the end of the given string like follows:
function markNumber(num) {
return num.replace( /(0{1,})$/g, '<span>$1</span>')
}
const number = 1.2345670089
let renderStyle1 = ''
let renderStyle2 = ''
const string = String(number) + '.'
const parts = string.split('.')
const decimals = parts[1]
const decimalsArray = Array.from(decimals);
// From MDN: The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. Otherwise -1 is returned.
const firstIndexOfZero = decimalsArray.findIndex(x => x === '0');
// From MDN: The slice() method returns a shallow copy of a portion of an array into a new array object selected from start to end (end not included) where start and end represent the index of items in that array. The original array will not be modified.
if(firstIndexOfZero === -1){
renderStyle1 = parts[0] + parts[1]
} else {
renderStyle1 = parts[0] + decimalsArray.slice(0, firstIndexOfZero).join('') // using .join method to convert array to string without commas
renderStyle2 = decimalsArray.slice(firstIndexOfZero, decimalsArray.length).join('') // using .join method to convert array to string without commas
}
console.log(renderStyle1) // "1234567"
console.log(renderStyle2) // "0089"
Messy, and, probably, can be improved, but this should work:
let re = /(\d*\.[1-9]*?)(0.*)/;
["1000", "1.01", "1.10", "1.000", "1.34043"].map((str) =>
str.split(re).filter((entry) => entry !== "")
);
Here's my regex function
const number = ['0.1000', '2.534300', '1.2000', '1.004334000'];
function split_float(num) {
const reg = /^(\d*\.\d*[^0])(0*)$/g;
const [, ...matches] = [...num.matchAll(reg)][0];
return matches;
}
console.log(number.map(split_float));
here is my answer. It uses split and substring to achieve what you want. Tried it in w3school's tryit editor. Handles all of your data in screenshot pretty well:
function myFunction() {
var str = "0.01200";
var partone = str.split(".")[0];
var temp = str.split(".")[1];
for (var i=0; i<temp.length; i++){
if (temp[i] != 0 && temp[i+1] == 0){
break;
}
}
var parttwo = temp.substring(i+1);
partone = partone + "." + temp.substring(0, i+1);
var res = "partOne = " + partone + " and partTwo = " + parttwo;
document.getElementById("demo").innerHTML = res;
}
Here is the screenshot:
If I have a string a12c56a1b5 then out put should be a13b5c56 as character a is repeated twice so a12 becomes a13
I have tried this:
function stringCompression (str) {
var output = '';
var count = 0;
for (var i = 0; i < str.length; i++) {
count++;
if (str[i] != str[i+1]) {
output += str[i] + count;
count = 0;
}
}
console.log(output); // but it returns `a11121c15161a111b151` instead of `a13b5c56`
}
It is happening because the code is counting the occurrence of each element and appending it, even the numbers in the string.
In this code,
for (var i = 0; i < str.length; i++) {
count++;
if (str[i] != str[i+1]) {
output += str[i] + count;
count = 0;
}
}
in first iteration i = 0, str[i] = 'a' and str[i + 1] = '1' for the given string a12c56a1b5 which are not equal hence, it will generate the output as a1 for first iteration, then a111 for second iteration since str[i] = '1' and str[i + 1] = '2' now, and so on.
We can achieve this by first separating the characters from the count. Assuming, that there would be characters from a-z and A-Z only followed by the count. We can do something like this, str.match(/[a-zA-Z]+/g) to get the characters: ["a", "c", "a", "b"] and str.match(/[0-9]+/g) to get their counts: ["12", "56", "1", "5"], put them in an object one by one and add if it already exists.
Something like this:
function stringCompression(str) {
var characters = str.match(/[a-zA-Z]+/g);
var counts = str.match(/[0-9]+/g);
var countMap = {};
for (var i = 0; i < characters.length; i++) {
if (countMap[characters[i]]) {
countMap[characters[i]] += parseInt(counts[i]);
} else {
countMap[characters[i]] = parseInt(counts[i]);
}
}
var output = Object.keys(countMap)
.map(key => key + countMap[key])
.reduce((a, b) => a + b);
console.log(output);
}
stringCompression('a12c56a1b5')
Using regex to extract word characters and numbers. Keeps an object map res to track and sum up following numbers. sorts and converts back to a string.
As an example, the for-of loop iteration flow with str=a12c56a1b5:
c='a', n='12'
res['a'] = (+n = 12) + ( (res['a'] = undefined)||0 = 0)
or ie: res['a'] = 12 + 0
c='c', n='56'
res['c'] = 56 + 0
c='a', n='1'
res['a'] = 1 + (res['a'] = 12 from iteration 1.) = 13
c='b', n='5'
res['b'] = 5 + 0
thus res = { 'a': 13, 'c': 56, 'b': 5 } after the for-of loop finishes
function stringCompression (str) {
// build object map with sums of following numbers
const res = {}
for(const [,c,n] of str.matchAll(/(\w+)(\d+)/g))
res[c] = +n + (res[c]||0)
// convert object map back to string
output = Object.entries(res)
output.sort(([a],[b])=>a<b ? -1 : a>b ? 1 : 0)
output = output.map(([a,b])=>`${a}${b}`).join('')
console.log(output); // but it returns `a11121c15161a111b151` instead of `a13b5c56`
}
stringCompression('a12c56a1b5')
[,c,n] = [1,2,3] is equivalent to c=2, n=3. It is called destructuring.
matchAll matches on a regex. It's a relatively new shorthand for calling .exec repeatedly to execute a regular expression that collects all the results that the regular expression matches on.
(\w+)(\d+) is a regex for two capture groups,
\w+ is for one or more alpha characters, \d+ is for one or more digits.
for(const [,c,n] of str.matchAll...) is equivalent to:
for each M of str.matchAll...
const c = M[1], n = M[2]`
res[c]||0 is shorthand for:
"give me res[c] if it is truthy (not undefined, null or 0), otherwise give me 0"
+n uses the unary operator + to force an implicit conversion to a number. JavaScript specs for + unary makes it convert to number, since + unary only makes sense with numbers.
It is basically the same as using Number(n) to convert a string to an number.
Conversion back to a string:
Object.entries converts an object {"key":value} to an array in the form of [ [key1, value1], [key2, value2] ]. This allows manipulating the elements of an object like an array.
.sort sorts the array. I destructured the keys to sort on the keys, so "a" "b" "c" are kept in order.
.map takes an array, and "maps" it to another array. In this case I've mapped each [key,value] to a string key+value, and then taking the final mapped array of key+value strings and joined them together to get the final output.
In case it asks you to sort it alphabetically, I added #user120242's sorting code snippet to #saheb's entire answer (in between Object.keys(countMap) and .map(...). That worked for me. I tried using #user120242's whole answer, but it did not pass all the tests since it did not add the repeated letters for longer strings. But #user120242's answer did work. It just need to be sorted alphabetically and it passed all the test cases in HackerRank. I had this question for a coding assessment (called "Better Coding Compression").
P.S. I also removed checking the capital letters from #saheb's code since that wasn't required for my coding challenge.
Here's how mine looked like:
function stringCompression(str) {
var characters = str.match(/[a-zA-Z]+/g);
var counts = str.match(/[0-9]+/g);
var countMap = {};
for (var i = 0; i < characters.length; i++) {
if (countMap[characters[i]]) {
countMap[characters[i]] += parseInt(counts[i]);
} else {
countMap[characters[i]] = parseInt(counts[i]);
}
}
var output = Object.keys(countMap)
.sort(([a],[b])=>a<b ? -1 : a>b ? 1 : 0)
.map(key => key + countMap[key])
.reduce((a, b) => a + b);
console.log(output);
}
stringCompression('a12c56a1b5')
I am trying to create a function compare() which when given an even letter of the alphabet returns the letter of index one below it and when given an odd letter of the alphabet returns the letter of index one above it (up to the letter 'e'). As such:
function compare(letter) {
var arr = {'a':'b', 'b':'a', 'c':'d', 'd':'c', 'e':'f', 'f':'e'}
return arr[letter]
}
The problem is that this array is going to be very long, and I feel like repeating each element in reverse is a bit of a waste. Is there a way of modifying the function so that I can store something like
arr={'a':'b', 'c':'d', 'e':'f'}
Instead of
arr={'a':'b', 'b':'a', 'c':'d', 'd':'c', 'e':'f', 'f':'e'}+
You don't need an object or array for this, you can use the char code to determine what the new code should be. Something like so
function getLetter(letter) {
var code = letter.charCodeAt(0);
var newCode = code % 2 == 0 ? code - 1 : code + 1;
return String.fromCharCode(newCode);
}
console.log(getLetter('a'));
console.log(getLetter('b'));
console.log(getLetter('c'));
console.log(getLetter('d'));
console.log(getLetter('e'));
console.log(getLetter('f'));
I think you are misunderstanding the array concept.
arr = {'a':'b', 'b':'a', 'c':'d', 'd':'c', 'e':'f', 'f':'e'} is not an array, but a Hash.
The correct way should be:
function compare(letter){
var arr = ['a','b','c','d','e','f']
var index = arr.indexOf(letter)
return index % 2 == 0 ? arr[index + 1] : arr[index - 1]
}
indexOf returns the position of the item you are checking. Then we check if it's odd or even and return the below/above corresponding letter.
Just check if it's even or odd, and return the letter above/below.
function compare(letter) {
var code = letter.charCodeAt(0);
if (code % 2) {
return String.fromCharCode(code + 1);
} else {
return String.fromCharCode(code - 1);
}
}
Example output:
compare('a')
"b"
compare('c')
"d"
compare('b')
"a"
compare('d')
"c"
const alphabet = ["a", "b", "c", "d", "e"];
const pairs = alphabet.reduce((acc, letter, index) => {
acc[letter] = alphabet[index+1] || alphabet[0];
return acc;
}, {});
console.log(pairs)
I'm trying to write a function that returns the index of a specific occurrence of a specific character from a string. However, I can only get it to successfully return the 1st or 2nd index. My function is as follows:
function getIndex(str,char,n) {
return str.indexOf(char, str.indexOf(char) + n-1);
}
Entering these tests only works for the first 2:
getIndex('https://www.example.example2.co.uk','.',2) // successfully returns 19
getIndex('https://www.example.example2.co.uk','.',1) // successfully returns 11
getIndex('https://www.example.example2.co.uk','.',3) // unsuccessfully returns 19
Does anyone have any ideas about how this could work for more than 2 instances? An example of how I'm using it would be to get the following:
var str = 'https://www.example.example2.co.uk';
str.substring(31); // returns .uk
str.substring(28, 31); // returns .co
Thanks for any help here.
You can use split, slice & join to achieve your requirement.
Logic
First split your string with char then use slice to join split values upto nth occurrence. Then simply join with char. It's length will be your answer.
Check below.
function getIndex(str, char, n) {
return str.split(char).slice(0, n).join(char).length;
}
console.log(getIndex('https://www.example.example2.co.uk', '.', 2)) // returns 19
console.log(getIndex('https://www.example.example2.co.uk', '.', 1)) // returns 11
console.log(getIndex('https://www.example.example2.co.uk', '.', 3)) // returns 28
In your code, you are not specifying nth occurance
str.indexOf(char, str.indexOf(char) + n-1);
Here you are trying to skip str.indexOf(char) + n-1 characters and continue the search
Try this function
function getIndex(str,char,n) {
return str.split('')
.map((ch,index)=>ch===char?index:-1)
.filter(in=>in!=-1)[n-1];
}
Say string is Hello and you are looking for 2nd l
Split the string into characters [H,e,l,l,0]
map them to index if it is the character you are looking for
[-1,-1,2,3,-1]
Filter all -1 [2,3]
Take the 2nd index using n-1 that is 3
const search = '.';
const indexOfAll = (arr, val) => arr.reduce((acc, curr, i) => (curr === val ? [...acc, i] : acc), []);
indexOfAll(Array.from('https://www.example.example2.co.uk'), search);
=> [ 11, 19, 28, 31 ]
function findIndex(str, searchCharacter, n){
var length = str.length, i= -1;
while(n-- && i++<length ){
i= str.indexOf(searchCharacter, i);
if (i < 0) break;
}
return i;
}
var index = findIndex('https://www.example.example2.co.uk','.',3);
console.log(index);
////
// 28
////
here is the fastest solution
function getIndex(str, character, n) {
return str.split(character, n).join(character).length;
}
var v1 = getIndex("https://www.example.example2.co.uk", ".", 1);
var v2 = getIndex("https://www.example.example2.co.uk", ".", 2);
var v3 = getIndex("https://www.example.example2.co.uk", ".", 3);
var v4 = getIndex("https://www.example.example2.co.uk", ".", 4);
var v5 = getIndex("https://www.example.example2.co.uk", ".", 5);
console.log(v1, v2, v3, v4, v5);
You could also use the regex exec method:
function getIndex(str, find, occ) {
var regex = new RegExp(`\\${find}`, 'g');
let arr, count = 0;
while ((arr = regex.exec(str)) !== null) {
if (++count == occ) return regex.lastIndex - 1;
}
}
const a = getIndex('https://www.example.example2.co.uk','.',2);
const b = getIndex('https://www.example.example2.co.uk','.',1);
const c = getIndex('https://www.example.example2.co.uk','.',3);
console.log(a, b, c);