Sum strings that have an optional slash in them - javascript

I need to sum all of the values in an array of strings, some of which are empty, some are normal integers, some are separated by slashes. I have it working when the values are just integers or empty, but not when they are separated by slashes.
//this works and should total 30
//var data = ["","1","","2","3","10","14"];
//this doesn't work and should total 166, not 128
var data = ["","1","2","5 / 35","","100 / 3", "20"];
var sum = data.reduce(function (a, b) {
a = parseInt(a, 10);
if(isNaN(a)){ a = 0; }
b = parseInt(b, 10);
if(isNaN(b)){ b = 0; }
return a + b;
});
console.log(sum);
Here is a codepen with the example...
https://codepen.io/murphydan/pen/GGWwgE?editors=0011

I suppose you simply want to sum all numbers in the array, no matter what's the elements content (as your desired result is 166). You can simply split and use another reduce
const data = ["", "1", "2", "5 / 35", "", "100 / 3", "20"];
const res = data.reduce((a, b) => {
const t = b.split('/');
return a + t.reduce((x, y) => x + Number(y), 0);
}, 0);
console.log(res);
If you need it even more flexible, for example if the slash could also be something else, like a comma, dash or whatever, you could split by non digits too. split(/\D/). This will create some more array entries as every whitespace gets another entry, but that doesn't change the result.

I like to avoid nesting functions like .reduce().
Like:
const data = ["", "1", "2", "5 / 35", "", "100 / 3", "20"];
const res = data.join(' ')// to a single string
.replace(/\//g, '')// replace all slashes
.split(/\s/)// split on whitespace to array
.reduce((acc, n) => (acc + (parseInt(n) || 0)) ,0);// sum all numbers
console.log(res);

Related

Adding numeric values in a string together

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);

translating a standard arithmetic string into a BODMAS string delimited by pipes

I need to find a way of translating a standard arithmetic formula written as a string into another string in the format of a calculation implements BODMAS as a stack of values and operations where each are delimited by a pipes read from left to right.
I do not want the result of the formula, I'm trying to write a javascript function that can be added to an HTML page where a user can enter a formula (example 10 * 6 / 2), have the formula validated, then translated into another formula (result is 10|6|multiply|2|divide). Its translating from one string format to another.
I already have another function that knows how to process formulas written this way, I just need to avoid forcing users to have to write a formula in an unfamiliar way so I need this translation done on the interface.
What I've tried so far is using a split function but I haven't been able to work out how to extend it to create the bodman_value. My javascript skills are basic as. Here's where I got to, any advice of how to approach it appreciated.
const str = '10 * 6 / 2';
const value_1 = str.split(' ');
console.log(value_1[0]);
// expected output: "10"
const operator_1 = str.split(' ');
console.log(operator_1[1]);
// expected output: "*"
const value_2 = str.split(' ');
console.log(value_2[2]);
// expected output: "6"
const operator_2 = str.split(' ');
console.log(operator_2[3]);
// expected output: "/"
const value_3 = str.split(' ');
console.log(value_3[4]);
// expected output: "2"
// expected output: Array ["10","*","6","/", "2"]
// assuming operator always at arroay 'odd' position (strCopy array is 0-4)
// count operators by number of odd positions in array
// then loop to get operator name of each array f_operator
IF strCopy.[i] = "*" THEN f_operator.[i] = "multiply"
IF strCopy.[i] = "+" THEN f_operator.[i] = "add"
IF strCopy.[i] = "-" THEN f_operator.[i] = "subtract"
IF strCopy.[i] = "/" THEN f_operator.[i] = "divide"
var bodman_value
// FOR loop f from 0 to array count
bodman_value = strCopy.[f]] + "|" + strCopy.[f+2] + "|" + operator.[f]
IF array count > 3
bodman_value = bodman_value + "|"
else
Thanks.
If you have the pattern
value [operator, value]+
you could just switch the repeating operator value parts to
value [value, operator]+
var operators = {
'*': 'multiply',
'/': 'divide'
},
string = '10 * 6 / 2',
tokens = string.split(/\s+/),
i = 0,
result = [tokens[i++]];
while (i < tokens.length) {
result.push(tokens[i + 1], operators[tokens[i]]);
i += 2;
}
console.log(result.join('|'));
An even shorter approach with a regular expression and a replacement function.
var operators = {
'*': 'multiply',
'/': 'divide',
'+': 'plus'
},
string = '24 + 6 / 10 * 100',
result = string.replace(/\s+([^\s]+)\s+([^\s]+)/g, (_, o, v) => `|${v}|${operators[o]}`);
console.log(result);

Formatting array elements into Uppercase and lower case format using JavaScript

I have an array of strings. I need to display those elements into proper format. Like this example.
let array1 = ["WORLDWIDE_AGRICULTURAL - CA"," WORLDWIDE_INDUSTRIAL - MX"]
I have to display it like below:
let formattedArray = ["Worldwide Agricultural - CA","Worldwide Industrial - MX"]
There are multiple of elements so I have to save formatted strings into array. I have tried but it is not coming properly.
Any help is much appreciated.
if(array1.indexOf("WORLDWIDE_AGRICULTURAL")>=0 || array1.indexOf(" WORLDWIDE_INDUSTRIAL") >=0){ var locname1 = array1.split('-'); var locname2 =locname1[0].trim(); var locname3 = locaname1[1].trim(); var formattedArray = locname2.toUpperCase()+ ' - '+locname3.toUpeerCase();
But, it is coming in uppercase and i have to all formatted elements into array.
You could use .map() with .replace() and the replacement method to convert your capital groups into lowercase groups like so:
const array1 = ["WORLDWIDE_AGRICULTURAL - CA"," WORLDWIDE_INDUSTRIAL - MX"];
const res = array1.map(str =>
str.replace(/(\w)(\w+)_(\w)(\w+)/g, (_, a, b, c, d) =>
`${a}${b.toLowerCase()} ${c}${d.toLowerCase()}`
).trim()
);
console.log(res);
The expression first matchs the first character in the string and groups that in group a. It then groups the remaining characters in group b up until the underscore. Then, it groups the first character after the underscore (group c). Lastly, it groups the remaining characters up to the next space. Using the replacement method, we can change group b to lowercase, and group d to lowercase, giving you a capitalized string.
An alternate approach which would require less grouping is to extract the first character from the first and second group, and capitalize the rest:
const array1 = ["WORLDWIDE_AGRICULTURAL - CA"," WORLDWIDE_INDUSTRIAL - MX"];
const res = array1.map(str =>
str.replace(/(\w+)_(\w+)/g, (_, [a, ...b], [c, ...d]) =>
`${a}${b.join('').toLowerCase()} ${c}${d.join('').toLowerCase()}`
).trim()
);
console.log(res);
let array1 = ["WORLDWIDE_AGRICULTURAL - CA", " WORLDWIDE_INDUSTRIAL - MX"];
function titleCase(str) {
var splitStr = str.toLowerCase().split(' ');
for (var i = 0; i < splitStr.length; i++) {
if (splitStr[i].length > 2) {
splitStr[i] = splitStr[i].charAt(0).toUpperCase() + splitStr[i].substring(1);
} else {
splitStr[i] = splitStr[i].toUpperCase()
}
}
return splitStr.join(' ');
}
const formattedArray = array1.map((x) => titleCase(x));
console.log(formattedArray);
Here's what would match your current demonstrated requirement:
let array1 = ["WORLDWIDE_AGRICULTURAL - CA"," WORLDWIDE_INDUSTRIAL - MX"]
function formatter(str) {
let split = str.split("-")
let formattedFirst = split[0].replace(/_/g, " ")
.replace(/\w\S*/g, function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
});
return `${formattedFirst} - ${split[1]}`
}
let convertedArray = array1.map(formatter)
console.log(convertedArray);
First, it seems like you only want to format whats before the ' - ' so we split on that. Then using replace we turn the _ into ' ' after which we can convert to title casing by capitalizing the first letter and lower casing the rest. Afterwards, we recombine to restore the original format of the rest of the string

Flipping 0's and 1's from a natural number

I want to create a javascript function to flip 1's to 0's in a natural number and I'm out of Ideas to achieve this,
Actually, I had a couple of URL's, and I replaced all 0's from a query parameter with 1's and now I no longer know the original parameter value, because there were few 1's in the original parameter value and now both are mixed, so basically I screwed myself,
The only solution for me is to try flipping each 1 to 0 and then 0's to 1's and test each number as the parameter.
This is the parameter value (after replacing 0's with 1's)
11422971
using above input I want to generate numbers as follows and test each of these
11422970
10422971
10422970
01422971
As you can see only 1's and 0's are changing, the change according to binary,
Each position in your string can be one of n characters:
A "0" can be either "0" or "1"
A "1" can be either "0" or "1"
Any other character c can only be c
We can store this in an array of arrays:
"11422971" -> [ ["0", "1"], ["0, "1"], ["4"], ... ]
To transform your string to this format, you can do a split and map:
const chars = "11422971"
.split("")
.map(c => c === "1" || c === "0" ? ["1", "0"] : [ c ]);
Once you got this format, the remaining logic is to create all possible combinations from this array. There are many ways to do so (search for "array combinations" or "permutations"). I've chosen to show a recursive pattern:
const chars = "11422971"
.split("")
.map(c =>
c === "1" || c === "0"
? ["1", "0"]
: [ c ]
);
const perms = ([ xs, ...others ], s = "", ps = []) =>
xs
? ps.concat(...xs.map(x => perms(others, s + x, ps)))
: ps.concat(s);
console.log(perms(chars));
you can do it with a number like a string, and after parse it, something like that
var number= "12551";
number= number.replace("1","0");
The result of number will be "02550"
after that parse number to int
This will generate all permutations.
const generatePermutations = (number) => {
let digits = number.split('');
// find out which digits can be flipped
let digitPositions = digits.reduce((acc, val, i) => {
if (val === '0' || val === '1') acc.push(i);
return acc;
}, []);
// we're going to be taking things in reverse order
digitPositions.reverse();
// how many digits can we flip
let noBits = digitPositions.length;
// number of permutations is 2^noBits i.e. 3 digits means 2^3 = 8 permutations.
let combinations = Math.pow(2, digitPositions.length);
let permutations = [];
// for each permutation
for (var p = 0; p < combinations; p++) {
// take a copy of digits for this permutation
permutations[p] = digits.slice();
// set each of the flippable bits according to the bit positions for this permutation
// i = 3 = 011 in binary
for (var i = 0; i < noBits; i++) {
permutations[p][digitPositions[i]] = '' + ((p >> i) & 1);
}
permutations[p] = permutations[p].join('');
}
return permutations;
};
console.log(generatePermutations('11422970'));
In case your looking for a recursive approach:
function recursive(acc, first, ...rest) {
if(!first) return acc;
if(first == '0' || first == '1') {
var acc0 = acc.map(x => x + '0');
var acc1 = acc.map(x => x + '1');
return recursive([].concat(acc0, acc1), ...rest);
} else {
return recursive(acc.map(x => x + first), ...rest);
}
}
recursive([''], ...'11422971')
// output ["00422970", "10422970", "01422970", "11422970", "00422971", "10422971", "01422971", "11422971"]
This just counts in binary and fills out a template for each value.
function getPossibleValues(str) {
function getResult(n) {
let nIndex = 0;
const strValue = n.toString(2).padStart(nDigits, '0');
return str.replace(rxMatch, () => strValue.charAt(nIndex++));
}
const rxMatch = /[01]/g;
const nDigits = str.length - str.replace(rxMatch, '').length;
const nMax = Math.pow(2, nDigits);
const arrResult = [];
for(let n = 0; n<nMax; n++) {
arrResult.push(getResult(n));
}
return arrResult;
}
console.log(getPossibleValues('11422970'));
Thank you all to respond, you saved my life, btw the approach I used was,
0- convert the number into a string. (so we can perform string operations like split())
1- count the number of 1's in the string (let's say the string is "11422971", so we get three 1's, I used split('1')-1 to count)
2- generate binary of three-digit length,(ie from 000 to 111). three came from step 1.
2- break down the string to single chars, (we'll get
array=['1','1','4','2','2','9','7','1'] )
3- take the first binary number (ie b=0b000)
4- replace first 1 from the character array with the first binary digit of b (ie replace 1 with 0), similarly replace second 1 with the second binary digit of b and so on.
5- we'll get the first combination (ie "00422970")
5- repeat step 3 and 4 for all binary numbers we generated in step 2.

converting string to array of arrays and elements

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

Categories