Find the Oxidation States
Ruby, 288 255 bytes
->m{h={[?O]=>-2,%w[F Cl]=>-1,%w[H Li Na K Rb Cs Fr]=>1,%w[Be Mg Ca Sr Ba Ra]=>2};a=m.scan /([A-Z][a-z]*\d*)/;r=a.flat_map{|(b)|b=~/(\D+)(\d*)/;[a.size==1?0:h[h.keys.find{|v|v.include?$1}]]*($2=='' ? 1:$2.to_i)};r.map{|j|j||-((r-[p]).inject:+)/r.count(p)}}
Try it online!
- Saved 1 byte thanks to Jenkar
- Saved 32 more bytes by inlining definitions and removing parentheses
Ungolfed
oxidation_state = -> molecule {
h = {
%w[H] => 1,
%w[O] => -2,
%w[F] => -1,
%w[Cl] => -1,
%w[Li Na K Rb Cs Fr] => 1,
%w[Be Mg Ca Sr Ba Ra] => 2,
}
find_oxidation = -> a {
k = h.keys.find { |as| as.include?(a) }
h[k]
}
atoms = molecule.scan(/([A-Z][a-z]*\d*)/)
r = atoms.flat_map { |(a)|
a.match(/([^\d]+)(\d*)/)
[atoms.length == 1 ? 0 : find_oxidation[$1]] * ($2=='' ? 1 : $2.to_i)
}
r.map { |j|
sum = r.compact.inject(:+)
!j ? -sum / r.count(nil) : j
}
}