Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reduce a string expression like "20hc+2a+2hc+9op" to "22hc+2a+9op"

How to find and pair the alphabets after the numbers in a string in order to reduce one expression?

Lets assume we have a string like string = "20hc+2a+2hc+9op+330o+10op", and we want to find the pair which same alphabet after numbers. First we should do split.('+') and then we get an array [....], then we need to pair each alphabets after the numbers, to get something like below:

(20hc + 2hc) (2a) (9op+10op) (330o)

Finally, we need to sum the numbers for the matching pairs:

20+2 = 22hc
2 = 2a
9+10 = 19op
330 = 330o

To get a final result of:

22hc+2a+19op+330o

So, how can I approach this, it does not matter if they aren't sorted as long as the alphabet after numbers are same, in this case, could we use regex to match them ? or indexOf ?

like image 607
koplweou Avatar asked Feb 01 '19 00:02

koplweou


2 Answers

I think for readability, just use an indexOf pair conversion, and build a hash. For example:

const getPair = str => {
  const numbers = '0123456789'
  for (var i = 0; i < str.length; i++) {
    if(numbers.indexOf(str.charAt(i)) < 0){ break }
  }
  return [str.slice(i), i === 0 ? 1 : parseInt(str.slice(0, i))]
}
  
//const eq = '20hc+2a+2hc+9op+330o+10op'
const eq = 'a+2ab+3b+4c+5bc'

const hash = eq.split('+')
               .map(getPair)
               .reduce((r, [key, val]) => {
                 r[key] = r[key] ? r[key] + val : val
                 return r
               }, {})

const result = Object.entries(hash).map(([key, val]) => `${val}${key}`).join('+')

console.log(result)
like image 161
Matt Way Avatar answered Oct 02 '22 07:10

Matt Way


I will do this in two steps. The first step generates an object with the keys (alphabet letters) and the totals (sum of numbers) for each key. For this, we use String::split() and Array::reduce() in that order. An example of the generated object will be like:

{"hc": 22, "op": 19, ...}

The second step just formats the previous generated object to the desired output string. For this one we use Object.entries(), Array::map() and finally Array::join().

const input = "a+20hc+2a+2hc+9op+330o+10op";

// First, get keys and sum their total.

let res = input.split("+")
    .reduce((acc, curr) =>
    {
        let [match, val, key] = curr.match(/(\d*)(\w*)/);
        val = +val || 1;
        acc[key] = acc[key] ? acc[key] + val : val;
        return acc;
    }, {});

console.log(res);

// Now, format to the output string.

res = Object.entries(res).map(([x, y]) => y + x).join("+");
console.log(res);

However, you should note that the previous approach won't work if you have subtractions, but some minor changes can do the work:

const input = "-4a+20hc+2a+2hc+9op+330o+10op-340o";

// First, get keys and sum their total.

let res = input.split(/\+|(?=-)/)
    .reduce((acc, curr) =>
    {
        let [match, val, key] = curr.match(/(-*\d*)(\w*)/);
        val = +val || 1;
        acc[key] = acc[key] ? acc[key] + val : val;
        return acc;
    }, {});

console.log(res);

// Now, format to the output string.

res = Object.entries(res)
    .map(([x, y]) => y + x)
    .join("+")
    .replace(/\+-/, "-");

console.log(res);
like image 41
Shidersz Avatar answered Oct 02 '22 09:10

Shidersz