I have a string returned from an endpoint in which I need to add certain parts of the string together in order to produce two different values.
Example response:
149,226;147,226;146,224
Now I know I can use the unary plus operator to force the string to be treated as a number like so.
var num1 = '20',
num2 = '22';
var total = (+num1) + (+num2);
or I could do some conversion like so
var number1 = parseInt(num1);
var number2 = parseInt(num2);
var total = number1 + number2;
either of these work fine however this is not what I am looking for exactly.
I want to take this result
149,226;147,226;146,224
Then add all the numbers before the first comer together so that would be (149, 147, 146) to produce one result and then add all the number after the second comer together (226, 226, 224).
I know I probably need some sort of reg expression for this I just dont know what.
You can just use string.split, twice, one for the ; and then again for the ,. And put this through array.reduce.
eg.
var str = '149,226;147,226;146,224';
var result = str.split(';')
.reduce((a,v) => {
var vv = v.split(',');
a[0] += vv[0] | 0;
a[1] += vv[1] | 0;
return a;
}, [0, 0]);
console.log(result);
For a more generic solution, that could handle any number of sub strings, eg. 1,2,3;4,5,6, and also handle alternative split types, and cope with extra , or ;.
function sumStrings(str, outerSplit, innerSplit) {
return str.split(outerSplit || ';')
.filter(Boolean)
.reduce((a,v) => {
v.split(innerSplit || ',')
.filter(Boolean)
.forEach((v,ix) => {
a[ix] = (a[ix] | 0) + (v | 0);
});
return a;
}, []);
}
console.log(sumStrings(
'149,226;147,226;146,224'
));
console.log(sumStrings(
'149.226.201|147.226.112.|146.224.300|',
'|','.'));
//how about total of totals?
console.log(sumStrings(
'149,226;147,226;146,224'
).reduce((a,v) => a + v));
.as-console-wrapper {
min-height: 100%
}
You could do:
const myString = '149,226;147,226;146,224';
/*
* 1. you split the string by ';' to obtain an array of string couples
* then you split each couple by ','. In this way you end up with an array like this:
* [['149', '266'], ['147', '266'], ['146', '264']]
*/
const myNumbers = myString.split(';').map(numCouple => numCouple.split(','));
/*
* 2. you use Array.prototype.reduce() to calculate the sums
*/
const sum1 = myNumbers.reduce((sum, item) => {
return sum += parseInt(item[0]);
}, 0);
const sum2 = myNumbers.reduce((sum, item) => {
return sum += parseInt(item[1]);
}, 0);
// or, as an alternative:
const sumsObj = myNumbers.reduce((obj, item) => {
obj.sum1 += parseInt(item[0]);
obj.sum2 += parseInt(item[1]);
return obj;
}, { sum1: 0, sum2: 0 });
// or also:
const sumsArr = myNumbers.reduce((acc, item) => {
acc[0] += parseInt(item[0]);
acc[1] += parseInt(item[1]);
return acc;
}, [0, 0]);
// test
console.log('sum1:', sum1);
console.log('sum2:', sum2);
console.log('--------------');
console.log('sum1:', sumsObj.sum1);
console.log('sum2:', sumsObj.sum2);
console.log('--------------');
console.log('sum1:', sumsArr[0]);
console.log('sum2:', sumsArr[1]);
without using regex, one possible solution:
var c = '149,226;147,226;146,224'
var d = c.split(";")
var first = d.map(x=>Number(x.split(",")[0]))
var second= d.map(x=>Number(x.split(",")[1]))
console.log(first)
console.log(second)
let resultFirst = first.reduce((a,b) => a + b, 0);
let resultSecond = second.reduce((a,b) => a + b, 0);
console.log(resultFirst)
console.log(resultSecond)
Below supplies regex to String's .split to get the numbers by themselves. Then you could add every other number but I don't see why not just add them all in order.
const str = '149,226;147,226;146,224'
const total = str.split(/[;,]/).map(Number).reduce((a, b) => a + b)
console.log('total', total)
I got this one running:
const nums = ('149,226;147,226;146,224');
var firstNums = nums.match(/(?<=[0-9]*)[0-9]+(?=,)/gs);
var secondNums = nums.match(/(?<=[0-9]*)[0-9]+(?=;|$)/gs);
console.log(firstNums, secondNums);
let sumFirstNums = 0,
sumSecondNums = 0;
firstNums.map(x => {
sumFirstNums += +x;
})
console.log(sumFirstNums)
secondNums.map(x => {
sumSecondNums += +x;
})
console.log(sumSecondNums)
//If you want the result in the same format:
const finalResult = `${sumFirstNums}, ${sumSecondNums};`
console.log(finalResult)
;)
For that string format, you could use a single pattern with 2 capturing groups matching 1+ more digits between a comma, and asserting a ; or the end of the string at the right.
You refer to the group values by indexing into the match of every iteration.
(\d+),(\d+)(?=;|$)
The pattern matches
(\d+) Capture group 1, match 1+ digits
, Match a comma
(\d+) Capture group 2, match 1+ digits
(?=;|$) Positive lookahead, assert directly to the right a ; or end of the string
See a regex demo.
let result1 = 0;
let result2 = 0
for (const match of "149,226;147,226;146,224".matchAll(/(\d+),(\d+)(?=;|$)/g)) {
result1 += +match[1]
result2 += +match[2]
}
console.log(result1, result2);
Related
I have an integer containing various digits, I want to remove 4th digit from an integer. How can I achieve that ?
Example :
let number = 789012345
Here I want to remove 0
Try this :
// Input
let number = 789012345;
// Convert number into a string
let numberStr = number.toString();
// Replace the 0 with empty string
const res = numberStr.replace(numberStr[3], '');
// Convert string into a number.
console.log(Number(res));
Rohìt Jíndal's answer is excellent. I just want to point out another way you could do this with string.replace and capturing groups.
function removeDigit(input, index) {
let exp = new RegExp(`^(\\d{${index}})(\\d)(.+)$`);
return parseInt(input.toString().replace(exp, '$1$3'));
}
let output = removeDigit(789012345, 3);
console.log(output); // 78912345
In this example, I have created a new RegExp object from a template literal in order to inject the index.
The first capturing group contains all digits up to the desired index. The second contains the digit we want to remove and the third contains the remainder of the string.
We then return an integer parsed from the string combination of only the first and third capturing groups.
You can follow this procedure:
Decide if you want to remove digits by index or by value, the following demo will remove by value, which means it will remove all values that match
Convert the number into a string
Convert the string to an array with Array.from
Use Array#filter to remove target digit(s)
Use Array#join to create a string
Use + to convert to string back into a numeric value
const n = 789012345;
const m = +Array.from( n.toString() ).filter(num => +num !== 0).join("");
console.log( m );
let numberWithoutADigit = removeIthDigitFromNumber(789012345, 4);
function removeIthDigitFromNumber(n, i){
//convert the number n to string as an array of char
let o = (n + '').split('');
//remove the item at the index i (0 based) from the array
o.splice(i, 1);
//rebuilds the string from the array of char and parse the string to return a number
let number = parseInt(o.join(''));
return number;
}
let number = 789012345
let i = 3 // index 3, 4th digit in number
let arr = number.toString().split("").filter((value, index) => index!==i);
// ['7', '8', '9', '1', '2', '3', '4', '5']
let new_number = parseInt(arr.join(""))
// 78912345
console.log(new_number)
let x = 789012345
var nums = [];
let i = 0, temp = 0;
while(x > 1){
nums[i++] = (x % 10);
x = (x - (x % 10)) / 10;
}
var cnt = 0;
for(--i; i >= 0; i--){
if (cnt++ == 3) continue;
temp = temp * 10 + nums[i];
}
I am trying to find a simple way to perform a set of javascript math operations without using eval() function. Example: 1+2x3x400+32/2+3 and it must follow the PEMDAS math principle. This is what I have, but it doesn't work exactly it should.
function mdas(equation) {
let operations = ["*", "/", "+", "-"];
for (let outerCount = 0; outerCount < operations.length; outerCount++) {
for (let innerCount = 0; innerCount < equation.length; ) {
if (equation[innerCount] == operations[outerCount]) {
let operationResult = runOperation(equation[innerCount - 1], operations[outerCount], equation[innerCount + 1]);
var leftSideOfEquation = equation.substr(0, equation.indexOf(innerCount - 1));
var rightSideOfEquation = equation.substr(equation.indexOf(innerCount), equation.length);
var rightSideOfEquation = rightSideOfEquation.replace(rightSideOfEquation[0],String(operationResult));
equation = leftSideOfEquation + rightSideOfEquation;
innerCount = 0;
}
else {
innerCount++;
}
}
}
return "Here is it: " + equation; //result of the equation
}
If you don't want to use a complete library like mathjs - and you don't want to tackle creating your own script which would involve: lexical analysis, tokenization, syntax analysis, recursive tree parsing, compiling and output...
the simplest banal suggestion: Function
const calc = s => Function(`return(${s})`)();
console.log( calc("1+2*3*400+32/2+3") ); // 2420
console.log( calc("-3*-2") ); // 6
console.log( calc("-3 * + 1") ); // -3
console.log( calc("-3 + -1") ); // -4
console.log( calc("2 * (3 + 1)") ); // 8
My take at a custom MDAS
Here I created a Regex to retrieve operands and operators, accounting for negative values: /(-?[\d.]+)([*\/+-])?/g.
Firstly we need to remove any whitespace from our string using str.replace(/ /g , "")
Using JavaScript's String.prototype.matchAll() we can get a 2D array with all the matches as [[fullMatch, operand, operator], [.. ] we can than further flatten it using Array.prototype.flat()
Having that flattened array, we can now filter it using Array.prototype.filter() to remove the fullMatch -es returned by the regular expression and remove the last undefined value.
Define a calc Object with the needed operation functions
Iterate over the MDAS groups */ and than +- as regular expressions /\/*/ and /+-/
Consume finally the array of matches until only one array key is left
let str = "-1+2 * 3*+400+-32 /2+3.1"; // 2386.1
str = str.replace(/ +/g, ""); // Remove all spaces!
// Get operands and operators as array.
// Remove full matches and undefined values.
const m = [...str.matchAll(/(-?[\d.]+)([*\/+-])?/g)].flat().filter((x, i) => x && i % 3);
const calc = {
"*": (a, b) => a * b,
"/": (a, b) => a / b,
"+": (a, b) => a + b,
"-": (a, b) => a - b,
};
// Iterate by MDAS groups order (first */ and than +-)
[/[*\/]/, /[+-]/].forEach(expr => {
for (let i = 0; i < m.length; i += 2) {
let [a, x, b] = [m[i], m[i + 1], m[i + 2]];
x = expr.exec(x);
if (!x) continue;
m[i] = calc[x.input](parseFloat(a), parseFloat(b)); // calculate and insert
m.splice(i + 1, 2); // remove operator and operand
i -= 2; // rewind loop
}
});
// Get the last standing result
console.log(m[0]); // 2386.1
It's a little hacky, but you can try something like this:
var eqs = [
'1+2*3*4+1+1+3',
'1+2*3*400+32/2+3',
'-5+2',
'3*-2',
];
for(var eq in eqs) { console.log(mdas(eqs[eq])); }
function mdas(equation) {
console.log(equation);
var failsafe = 100;
var num = '(((?<=[*+-])-|^-)?[0-9.]+)';
var reg = new RegExp(num + '([*/])' + num);
while(m = reg.exec(equation)) {
var n = (m[3] == "*") ? m[1]*m[4] : m[1]/m[4];
equation = equation.replace(m[0], n);
if(failsafe--<0) { return 'failsafe'; }
}
var reg = new RegExp(num + '([+-])' + num);
while(m = reg.exec(equation)) {
var n = (m[3] == "+") ? 1*m[1] + 1*m[4] : m[1]-m[4];
equation = equation.replace(m[0], n);
if(failsafe--<0) { return 'failsafe'; }
}
return equation;
}
I have a series of varying strings which I need to turn into arrays on every second occurrence of \n, for simplicity please consider the next example:
const str = 'banana\napple\nmango\n3.5'
//I have tried and failed with:
const arr = str.split(/(^\n)+\n(^\n)+/)
// Result should be:
// const arr = ['banana\napple', 'mango\n3.5']
Do I have to use a loop here or what?
You could take match instead of split by taking some non breaking character, a breaking character and other non breking character.
const
string = 'banana\napple\nmango\n3.5',
result = string.match(/[^\n]+\n[^\n]+/g);
console.log(result);
Damn this is an ugly approach:
let t1 = performance.now();
const result = 'banana\napple\nmango\n3.5'
.split('\n')
.map((str, i, arr) => (i % 2) === 0 ? str + '\n' + arr[i+1] : null )
.filter((str) => str !== null);
let t2 = performance.now();
console.log(result, t2-t1 + 'μs');
I have a string where common characters are repeated.
For example
x1234,x2345,x3456,x4567,x5678,x6789
I'm trying to replace every nth occurrence of the character "x" starting from the first occurrence with the character "d" using javascript.
The final output should be as follows
d1234,x2345,d3456,x4567,d5678,x6789
You could add a counter and replace by using a remainder for checking.
function replace(string, char, repl, n) {
var i = 0;
return string.replace(new RegExp(char, 'g'), c => i++ % n ? c : repl);
}
console.log(replace('x1234,x2345,x3456,x4567,x5678,x6789', 'x', 'd', 2));
console.log(replace('x1234,x2345,x3456,x4567,x5678,x6789', 'x', 'd', 3));
function replaceNth(str, n, newChar) {
const arr = str.split(',');
return arr.map((item, i) => (i % n === 0) ? item.replace('x', newChar) : item).join(",")
}
const str = 'x1234,x2345,x3456,x4567,x5678,x6789';
// replace for every second string value
console.log(
replaceNth(str, 2, 'd')
);
// replace for every third string value
console.log(
replaceNth(str, 3, 'e')
);
var splittedWords = "x1234,x2345,x3456,x4567,x5678,x6789".split(",")
var result = splittedWords.map((element, index) => index % 2 ? element : "d" + element.substring(1))
console.log(result.join(","))
Can use a regular expression to match a pattern
var str1 = "x1234,x2345,x3456,x4567,x5678,x6789"
var result1 = str1.replace( /x([^x]+(x|$))/g, 'd$1')
console.log(result1)
var str2 = "x1234,x2345,x3456"
var result2 = str2.replace( /x([^x]+(x|$))/g, 'd$1')
console.log(result2)
Explanation of reg exp: RegExper
or can just do a simple split, map, join
var str = "x1234,x2345,x3456,x4567,x5678,x6789"
var result = str.split(",") // split on comma
.map((part,index) => // loop over array
index % 2 === 0 // see if we are even or odd
? "d" + part.substring(1) // if even, remove first character, replace with 1
: part) // if odd, leave it
.join(",") // join it back together
console.log(result)
This assumes that the x is always after the comma, which may or may not be true. If not, then the logic needs to be more complicated.
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);