A redox reaction is a chemical reaction in which elements transfer electrons. One element loses electrons, while another gains electrons. Oxidation is the process where an element loses electrons, and reduction is the process where an element gains electrons. Since electrons have a negative charge, the oxidation number of an atom/ion changes during redox.

Quick refresher: oxidation number is the one in the top-right corner of a chemical symbol (default 0), number of moles is the number to the left of the symbol (default 1), and the number of atoms is in the bottom right (again, default 1). The total atoms of an element in a symbol is the product of the moles and the atoms. The number of atoms of an atom/ion does not affect its charge.

A half-reaction shows either the oxidation or reduction portion of a redox reaction, including the electrons gained or lost.

A reduction half-reaction shows an atom or an ion gaining one or more electrons while its oxidation number decreases. Example: Na+1 + 1e- → Na0

An oxidation half-reaction shows an atom or an ion losing one or more electrons while its oxidation number increases. Example: Na0 → Na+1 + 1e-

For the purposes of this challenge, you will only need to deal with redox reactions containing exactly two elements.

Every redox reaction has one half-reaction for the oxidation and one for the reduction. Here's how to write them:

Step Example
0. Start with a redox reaction. Zn + Br2 → Zn2+ + Br-
1. Break it into two partial half-reactions. Zn0 → Zn2+
Br20 → Br-
2. Balance the number of atoms on each side of the reactions, if necessary. Zn0 → Zn2+
3. Add electrons (e-) to balance the charge on each side of the reactions. Zn0 → Zn2+ + 2e-
Br20 + e- → 2Br-
4. Balance the number of electrons gained and lost by changing the coefficients (LCM of electrons from each) Zn0 → Zn2+ + 2e-
2Br20 + 2e-4Br-
5. Determine which reaction is the reduction, and which is the oxidation. Zn0 → Zn2+ + 2e- (Oxidation)
2Br20 + 2e- → 4Br- (Reduction)

Your task is, given a redox reaction, output its oxidation half-reaction and its reduction half-reaction. Input and output format is flexible; For example, you could take chemical symbols as a tuple of [name: string, moles: number = 1, atoms: number = 1, oxidation: number = 0], and a list of these for each side of the equation. Your output should indicate somehow which reaction is for the reduction and which is for the oxidation, e.g. by putting the oxidation first and reduction second.

Test cases

Cr + Fe2+ → Cr3+ + Fe

Oxidation: 2Cr0 → 2Cr3+ + 6e-
Reduction: 3Fe2+ + 6e- → 3Fe0

Pb + Ag+ → Pb2+ + Ag

Oxidation: Pb0 → Pb2+ + 2e-
Reduction: 2Ag+ + 2e- → 2Ag0

Fe3+ + Al → Fe2+ + Al3+

Oxidation: Al0 → Al3+ + 3e-
Reduction: 3Fe3+ + 3e- → 3Fe2+

Zn + Br2 → Zn2+ + Br-

Oxidization: Zn0 → Zn2+ + 2e-
Reduction: 2Br20 + 2e- → 4Br-

  • \$\begingroup\$ Note: I am in high school chemistry so there are probably some oversimplifications or mistakes in the explanation \$\endgroup\$
    – noodle man
    May 17, 2023 at 20:46
  • \$\begingroup\$ Will the redox reactions given as input only ever involve two elements? \$\endgroup\$
    – erfink
    May 18, 2023 at 0:56
  • 2
    \$\begingroup\$ @erfink Yes, that’s right. I didn’t want to overcomplicate it; clarified in the challenge. \$\endgroup\$
    – noodle man
    May 18, 2023 at 3:52
  • 1
    \$\begingroup\$ It's been a hot minute since I've done redox equations, but I'm pretty sure your bromine reduction in the worked example should be Br2 +2e- -> 2Br- \$\endgroup\$
    – jezza_99
    May 18, 2023 at 19:20

2 Answers 2


Mathematica v13.0+ 310 300 Bytes

Yeah, there's almost a built-in function for that...


E: -8 bytes by introducing sub-function n, -2 bytes by replacing Length[r] with Tr[1^r]


New in v13.0, Mathematica features built-in functions to parse, balance, and otherwise analyze chemical reactions along with entities for elements. The four test reactions can be entered as simple strings:

test1 = "Cr + Fe^2+ -> Cr^3+ + Fe";
test2 = "Pb + Ag^+ -> Pb^2+ + Ag";
test3 = "Fe^3+ + Al -> Fe^2+ + Al^3+";
test4 = "Zn + Br2 -> Zn^2+ + Br^-";

Applying the function Sort/@ReactionBalance[#][[1]]& does most of the heavy stoichiometric lifting (which we store to b for "balanced reaction") and yields the following formatted output:

balanced reactions

The remainder of my bodges are grappling with this custom datatype, while lamenting that there isn't a built in function for determining the half-reactions nor Lewis acids/bases. We store the elements & charge states for the reactants (k=Keys@b; and r=Keys@k;) and products (v=Values@b; and p=Keys@v;). We next do some kludges to determine the charge gained or lost by each element: n=#["NetCharge"]#&/@#2/.#1&;c=n[k,r]-n[v,p];, where we have used the "NetCharge" property to determine an element's ionic state (e.g., "Fe" vs "Fe^2+").

We store the nicely formatted string e=SuperScript["e","-"]; for electrons, because we definitely aren't making par on this hole of code golf. (N.B., Mathematica does have an entity for electrons, Entity["Particle","Electron"], but it doesn't play well with our later equations nor the ChemicalReaction data type.) Finally, we congeal all information into a horrific function to display the appropriately balanced half-reactions:


This outputs an array (list of lists) of the half-reactions, with the first entry being the string "Oxidation:" or "Reduction:", as shown for the four test cases: half reactions

This code could certainly be golfed down below 300 bytes (to perhaps ~250ish) with standard Mathematica tricks (e.g., Tr[1^r] instead of Length[r], remove redundancies for c, try to remove redundant logic within the Table[...If[..., and so forth), but it all gets rather ugly. Similarly, we could forsake Mathematica's custom ChemicalReaction wrapper and operate on our own specified input and output formats, but that's not as fun (for me).

As a final note, my function works fine so long as all reagents and products are single elements, but falters against more complex reactions, e.g., "(Cr(N2H4CO)6)4(Cr(CN)6)3+KMnO4+H2SO4 -> K2Cr2O7+MnSO4+CO2+KNO3+K2SO4+H2O", even though ReactionBalance can parse and balance it: messy redox reaction


Python, 293 bytes

def f(a,b,c,d):a[1]*=c[2];c[1]*=a[2];b[1]*=d[2];d[1]*=b[2];i,j=abs(a[3]*a[1]-c[3]*c[1]),abs(b[3]*b[1]-d[3]*d[1]);n=math.lcm(i,j);a[1],c[1],b[1],d[1]=a[1]*n//i,c[1]*n//i,b[1]*n//j,d[1]*n//j;r,o=[[a,c],[b,d]][::1-2*(a[3]<c[3])];return[[o[0]],[o[1],e:=["e",n,1,-1]]],[[r[0],e],[r[1]]]
import math

Attempt This Online!

I suspect this could be golfed much much further, but I can't be bothered trying to right now.

Takes 4 inputs, the two reactants and the two products, in the format described in the question. Outputs two lists in the order oxidation, reduction. Each output list is a half-equation in the form [[<REACTANTS>],[<PRODUCTS>]]. The link above includes some pretty print to make it easy to read and check. More readable version:

def f(a,b,c,d):
    # Correct number of molecules on each side of the equation

    # Find the charge difference of each half equation

    # Find the LCM of the charges
    # This gives the required number of electrons
    num_electrons = math.lcm(i, j)

    # Balance equations so both sides have equal electrons

    # Work out which side is oxidation and which is reduction

    # The electron molecule/s
    electrons = ["e", num_electrons, 1, -1]

    # The two half equations
    oxidation_output = [[oxidation[0]],[oxidation[1],electrons]]
    reduction_output = [[reduction[0],electrons],[reduction[1]]]

    return oxidation_output, reduction_output

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.