prime factorization, gcf, and lcm of any list of integers

Stephen Lukacs (2) iquanta.org/instruct/python
Remember: help::: GCF → "Fewest in Common" (simplify) | LCM → "Most of Each" (common denominator)

Enter your list of integers separated by commas:

list of integers: [12, 24, 28, 36]
primes: 12=1⋅22⋅3 | 24=1⋅23⋅3 | 28=1⋅22⋅7 | 36=1⋅22⋅32
gcf (fewest in common) = 4=1⋅22 (4)
lcm (most of each) = 504=1⋅23⋅32⋅7 (504)

"""
reference: https://iquanta.org/instruct/python ::: Math 1: GCF and LCM, prime factorization, gcf, and lcm of any list of integers ::: Stephen Lukacs, Ph.D. ©2022-01-23
"""
from py4web import URL, request
from yatl.helpers import *
from iquanta.mcp import is_str_int, str_to_int
from primefactors import factorize
from numpy import gcd as np_gcf, lcm as np_lcm

B = TAG['b']
BR = TAG['br/']
ilst = "12,24,28,36" if ('ilst' not in request.forms) else ilst
rtn = FORM("Remember: ", A("help", _href="https://calcworkshop.com/fractions/gcf-lcm/", target="help_gcf_lcm"), '::: ', B(XML('GCF  →')), ' "Fewest in Common" (simplify) | ', B(XML('LCM →')), ' "Most of Each" (common denominator)', *[BR()]*2, _method="post")
rtn.append(CAT("Enter your list of integers separated by commas: ", INPUT(_type="text", _name="ilst", _value=ilst), XML(' '), INPUT(_type="submit")))

def stringify_primes(primes):
    #primes is a dict of k=prime:v=exponent
    ni = 1
    for k, v in primes.items():
       ni *= k**v
    pstr = f"{ni}=1⋅"
    for i, (k, v) in enumerate(sorted(primes.items())):
       pstr += f'{k}{"<sup>"+str(v)+"</sup>" if (v > 1) else ""}&sdot;'
    pstr = pstr[:-6]
    return pstr, ni

#rtn = CAT('in here... "', ilst, '" ... ', A("start over", _href="/instruct/python/run/10"))
lst = [ ]
if isinstance(ilst, str):
    for i in ilst.replace(' ', "").split(","):
        if is_str_int(i):
            lst.append(str_to_int(i))
        else:
            raise Exception(f"{i} entry not an integer")
primes_lst = { }
for i in lst:
    primes = { }
    for p in factorize(i):
        if p in primes:
            primes[p] += 1
        else:
            primes[p] = 1
    primes_lst[i] = primes
primes_str = [ ]
for i in lst:
    primes_str.append(stringify_primes(primes_lst[i])[0])
#gcf...
factors_in_common = set( primes_lst[lst[0]]).intersection(*[ set(p) for p in primes_lst.values() ] )
gcf = { k:float('inf') for k in factors_in_common }
for l in lst:
    for k, v in primes_lst[l].items():
        if (k in gcf) and (v < gcf[k]):
            gcf[k] = v
#lcm...
factors_of_each = set().union(*[ set(p) for p in primes_lst.values() ])
lcm = { k:0 for k in factors_of_each }
for l in lst:
    for k, v in primes_lst[l].items():
        if (k in lcm) and (v > lcm[k]):
            lcm[k] = v
#rtn.append(CAT(BR(), "lst: ", str(lst), ' ... primes dict: ', XML(str(primes_lst)), primes_str, " ... factors_in_common: ",  str(factors_in_common), str(gcf), " ... factors_of_each: ",  str(factors_of_each), str(lcm)))

rtn.append(CAT(P("list of integers: ", lst, BR(), SPAN("primes: ", _style="font-weight:bold;"), XML("&emsp;|&emsp;".join(primes_str)), BR(), SPAN("gc", SPAN("f", _style="font-weight:bold;text-decoration:underline;"), " (", SPAN("fewest", _style="font-weight:bold;text-decoration:underline;"), " in common) = "), XML(f"{stringify_primes(gcf)[0]} ({np_gcf.reduce(lst)})"), BR(), SPAN("lc", SPAN("m", _style="font-weight:bold;text-decoration:underline;"), " (", SPAN("most", _style="font-weight:bold;text-decoration:underline;"), " of each) = "), XML(f"{stringify_primes(lcm)[0]} ({np_lcm.reduce(lst)})"),  _style="font-size: 16pt;")))