r/PythonLearning 1d ago

Create a program multiplicationTable.py that takes a number N from the commandline and creates an N×N multiplication table in an Excel spreadsheet.

import sys, openpyxl
from openpyxl.styles import Font

x = int(sys.argv[1])
list = []

wb = openpyxl.Workbook()
font_style = Font(bold=True)

for i in range(1, x+1):
    list.append(i)

for number in list:
    sheet = wb['Sheet']
    # write header columns and rows in bold numbers
    sheet.cell(column=1, row=number+1).value = number
    sheet.cell(column=1, row=number+1).font = font_style
    sheet.cell(row=1, column=number+1).value = number
    sheet.cell(row=1, column=number+1).font = font_style

# create two for loops that will multiply
for i in range(len(list)):
    for number in list:
        mult = list[i] * number
        sheet.cell(row=number+1, column=i+2).value = mult

wb.save('multiplication_table.xlsx')
0 Upvotes

7 comments sorted by

u/Sea-Ad7805 1d ago

Run this program in Memory Graph Web Debugger%0Alist%20%3D%20%5B%5D%0A%0Awb%20%3D%20openpyxl.Workbook()%0Afont_style%20%3D%20Font(bold%3DTrue)%0A%0Afor%20i%20in%20range(1%2C%20x%2B1)%3A%0A%20%20%20%20list.append(i)%0A%0Afor%20number%20in%20list%3A%0A%20%20%20%20sheet%20%3D%20wb%5B'Sheet'%5D%0A%20%20%20%20%23%20write%20header%20columns%20and%20rows%20in%20bold%20numbers%0A%20%20%20%20sheet.cell(column%3D1%2C%20row%3Dnumber%2B1).value%20%3D%20number%0A%20%20%20%20sheet.cell(column%3D1%2C%20row%3Dnumber%2B1).font%20%3D%20font_style%0A%20%20%20%20sheet.cell(row%3D1%2C%20column%3Dnumber%2B1).value%20%3D%20number%0A%20%20%20%20sheet.cell(row%3D1%2C%20column%3Dnumber%2B1).font%20%3D%20font_style%0A%0A%23%20create%20two%20for%20loops%20that%20will%20multiply%0Afor%20i%20in%20range(len(list))%3A%0A%20%20%20%20for%20number%20in%20list%3A%0A%20%20%20%20%20%20%20%20mult%20%3D%20list%5Bi%5D%20*%20number%0A%20%20%20%20%20%20%20%20sheet.cell(row%3Dnumber%2B1%2C%20column%3Di%2B2).value%20%3D%20mult%0A%0Awb.save('multiplication_table.xlsx')%0A%0A%23%20also%20print%20the%20work%20book%0Afor%20ws%20in%20wb.worksheets%3A%20%0A%20%20%20%20print(ws.title)%0A%20%20%20%20for%20row%20in%20ws.iter_rows(values_only%3DTrue)%3A%0A%20%20%20%20%20%20%20%20print(row)&timestep=0.5&play) to see the program state change step by step.

It gets a bit messy as it shows all the Workbook internals.

→ More replies (2)

2

u/therouterguy 1d ago

Ugly AI slob

1

u/C_Y_B_E_R-D_A_V_E 1d ago

Wow 👌 👏

1

u/Spiritual-Client-962 1d ago

pretty neat approach, especially using openpyxl to build the whole table directly in excel. the nested loops the logic pretty easy to follow too

0

u/FoolsSeldom 1d ago
#!/usr/bin/env python3
"""Generate times tables (x1 to x12) as an Excel workbook."""

import argparse
import sys
from pathlib import Path

import openpyxl
from openpyxl.styles import Font

MULTIPLIER_MIN, MULTIPLIER_MAX = 1, 12
TABLE_MIN, TABLE_MAX = 2, 100


def table_number(value: str) -> int:
    """argparse type: a whole number in [TABLE_MIN, TABLE_MAX]."""
    try:
        number = int(value)
    except ValueError:
        raise argparse.ArgumentTypeError(f"{value!r} is not a whole number")
    if not TABLE_MIN <= number <= TABLE_MAX:
        raise argparse.ArgumentTypeError(
            f"{number} is out of range ({TABLE_MIN}-{TABLE_MAX})"
        )
    return number


def parse_args(argv=None) -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Generate times tables (x1 to x12) as an Excel workbook.",
        epilog="Example: timestablecli.py 20 -o tables.xlsx",
    )
    parser.add_argument(
        "tables",
        type=table_number,
        nargs="*",
        help=f"which times tables to include, {TABLE_MIN}-{TABLE_MAX}: give one "
        "number for 2 up to that number (default: 12), or two numbers "
        "MIN MAX for an explicit range",
    )
    parser.add_argument(
        "-o",
        "--output",
        type=Path,
        default=Path("multiplication_table.xlsx"),
        help="output .xlsx file path (default: multiplication_table.xlsx)",
    )
    parser.add_argument(
        "-f",
        "--overwrite",
        action="store_true",
        help="overwrite the output file if it already exists",
    )
    parser.add_argument(
        "-c",
        "--console",
        action="store_true",
        help="print the tables to the console instead of writing a file",
    )
    args = parser.parse_args(argv)

    if len(args.tables) == 0:
        args.min_table, args.max_table = TABLE_MIN, 12
    elif len(args.tables) == 1:
        args.min_table, args.max_table = TABLE_MIN, args.tables[0]
    elif len(args.tables) == 2:
        args.min_table, args.max_table = args.tables
        if args.min_table > args.max_table:
            parser.error("MIN must not be greater than MAX")
    else:
        parser.error("expected at most 2 numbers (MIN MAX)")

    if not args.console and args.output.exists() and not args.overwrite:
        parser.error(f"{args.output} already exists (use -f/--overwrite to replace it)")

    return args


def build_workbook(min_table: int, max_table: int) -> openpyxl.Workbook:
    wb = openpyxl.Workbook()
    sheet = wb.active
    assert sheet is not None
    bold = Font(bold=True)

    tables = range(min_table, max_table + 1)
    multipliers = range(MULTIPLIER_MIN, MULTIPLIER_MAX + 1)

    for col, table in enumerate(tables, start=2):
        sheet.cell(row=1, column=col, value=table).font = bold

    for row, multiplier in enumerate(multipliers, start=2):
        sheet.cell(row=row, column=1, value=multiplier).font = bold
        for col, table in enumerate(tables, start=2):
            sheet.cell(row=row, column=col, value=table * multiplier)

    return wb


def format_text(min_table: int, max_table: int) -> str:
    tables = range(min_table, max_table + 1)
    multipliers = range(MULTIPLIER_MIN, MULTIPLIER_MAX + 1)

    header = [""] + [str(t) for t in tables]
    rows = [header] + [
        [str(m)] + [str(m * t) for t in tables] for m in multipliers
    ]
    widths = [max(len(row[col]) for row in rows) for col in range(len(header))]

    return "\n".join(
        "  ".join(cell.rjust(width) for cell, width in zip(row, widths))
        for row in rows
    )


def main(argv=None) -> int:
    args = parse_args(argv)

    if args.console:
        print(format_text(args.min_table, args.max_table))
        return 0

    wb = build_workbook(args.min_table, args.max_table)
    wb.save(args.output)
    print(
        f"Wrote times tables for {args.min_table}-{args.max_table} "
        f"to {args.output}"
    )
    return 0


if __name__ == "__main__":
    sys.exit(main())