Last active
July 19, 2019 07:53
-
-
Save jozsefs/e8e9ee46faffaaeddfdd26a8882eab6b to your computer and use it in GitHub Desktop.
molecules-to-atoms.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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