Skip to content

Instantly share code, notes, and snippets.

@jozsefs
Last active July 19, 2019 07:53
Show Gist options
  • Save jozsefs/e8e9ee46faffaaeddfdd26a8882eab6b to your computer and use it in GitHub Desktop.
Save jozsefs/e8e9ee46faffaaeddfdd26a8882eab6b to your computer and use it in GitHub Desktop.
molecules-to-atoms.js
// codewars exercise
const str = 'As2{Be4C5[BCo3(CO2)3]2}4Cu5';
function parseMolecule(formula) {
const BRACKET_OPENER_REGEXP = /\[|\{|\(/;
const BRACKET_CLOSER_REGEXP = /\]|\}|\)/;
const VALID_ATOM_REGEXP = /^[A-Z][a-z]?$/;
const MULTIPLIER_REGEXP = /^\d+/;
function createGroup(parent = {}) {
return {atoms : {}, groups : [], multiplier : 1, parent};
}
function extractGroups(str) {
const collection = createGroup();
let currentGroup = collection;
for (let i = 0; i < str.length; i++) {
const currentChar = str[i];
let isCloser = false;
let atom;
let multiplier = 1;
if (BRACKET_OPENER_REGEXP.test(currentChar)) {
// move down one level
const parentGroup = currentGroup;
currentGroup = createGroup(parentGroup);
parentGroup.groups.push(currentGroup);
continue;
}
else if (BRACKET_CLOSER_REGEXP.test(currentChar)) {
// move up one level
isCloser = true;
}
else if (VALID_ATOM_REGEXP.test(currentChar)) {
const currentChar = str[i];
const extendedChars = currentChar + str[i + 1];
atom = currentChar;
if (VALID_ATOM_REGEXP.test(extendedChars)) {
atom = extendedChars;
i++;
}
}
// look at following chars for multiplier
const multiplierMatch = str.slice(i + 1).match(MULTIPLIER_REGEXP);
if (multiplierMatch) {
const multiplierStr = multiplierMatch[0];
multiplier = +multiplierStr;
i += multiplierStr.length;
}
if (isCloser) {
currentGroup.multiplier = multiplier;
currentGroup = currentGroup.parent;
}
else {
const currentAtomCount = currentGroup.atoms[atom] || 0;
currentGroup.atoms[atom] = currentAtomCount + multiplier;
}
}
return collection;
}
function sumGroup(group, cumulatedMultiplier = 1, acc = {}) {
const {groups, multiplier, atoms} = group;
cumulatedMultiplier *= multiplier;
for (let i = 0; i < groups.length; i++) {
sumGroup(groups[i], cumulatedMultiplier, acc);
}
// Object.entries cannot be used yet on codewars :(
Object.keys(atoms).forEach(atom => {
const prevCount = acc[atom] || 0;
const count = atoms[atom];
acc[atom] = prevCount + (count * cumulatedMultiplier);
});
return acc;
}
const collection = extractGroups(formula);
return sumGroup(collection);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment