Skip to content

Latest commit

 

History

76 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 

Repository files navigation

Python_Training_Sets

Personally developed Python practice exercises.

Intro / Disclaimer

I developed these exercises as part of my Python practice process. I designed these exercises independently, and used AI assistants for tutoring and review. I'd try the code myself, share my attempt, and learn througu feedback. I'd then practice the exercises in my terminal to build procedural memory and develop fluency.

Exercise 1: City Abbreviations

cities["abbrev"]

Based on a dictionary of East Coast and West Coast cities, I abbreviate each city's name, depending on whether they contain one word or two. Starting with a dictionary of cities, create a function that updates cities["abbrev"] with esch city's acronym or abbreviation.

If a city name contains a space, returns an acronym of the first letter of each word. For single-word cities, use the first three letters and convert them to uppercase.

cities = {
    "East Coast": ["New York", "Boston", "Washington DC"],
    "West Coast": ["Los Angeles", "San Francisco", "Palo Alto"],
    "abbrev": []
}

for coast in ["East Coast", "West Coast"]:
    for city in cities[coast]:
        if " " in city:
            cities["abbrev"].append(
                city[0].upper()
                + city[city.index(" ") + 1].upper()
            )
        else:
            cities["abbrev"].append(city[:3].upper())

print(cities["abbrev"])

Output:

['NY', 'BOS', 'WD', 'LA', 'SF', 'PA']

Updated cities dict:

print(cities)

{'East Coast': ['New York', 'Boston', 'Washington DC'],
'West Coast': ['Los Angeles', 'San Francisco', 'Palo Alto'], 
'abbrev': ['NY', 'BOS', 'WD', 'LA', 'SF', 'PA']}

Note: This version uses the first two words of a city name with multiple words. For example, New York City becomes 'NY', not 'NYC'.

Exercise 2: Sunrise and Sunset Calculator:

sun_times(day, anchors)

Estimate sunrise and sunset timing for any date by calculating the date's position between two of four anchor points.

We'll assume the dates of the equinoxes and solstices are March 21, June 21, September 21, and December 21.

from datetime import date

spring = (3, 21)
summer = (6, 21)
fall = (9, 21)
winter = (12, 21)

def hm(h, m=0):
    return h * 60 + m

def sun_times(day, anchors):
    
    """
    anchors format: {
    spring:  (sunrise_minutes, sunset_minutes),
    summer:  (sunrise_minutes, sunset_minutes),
    fall:  (sunrise_minutes, sunset_minutes),
    winter: (sunrise_minutes, sunset_minutes)
    }
    Times are minutes after midnight.
    Example: 
    6:30 AM: hm(6, 30) = 360, 6:15 PM: hm(18, 15) = 1095
    """
    
# Determine which pair of anchor dates surrounds the target date in order to obtain a date index.

    month = day.month
    
    d = day.day
    
    if (month, d) >= spring and (month, d) < summer:
        last_anchor = spring
        next_anchor = summer
        day_index = (day - date(day.year, *spring)).days

    elif (month, d) >= summer and (month, d) < fall:
        last_anchor = summer
        next_anchor = fall
        day_index = (day - date(day.year, *summer)).days

    elif (month, d) >= fall and (month, d) < winter:
        last_anchor = fall
        next_anchor = winter
        day_index = (day - date(day.year, *fall)).days

    elif (month, d) >= winter:
        last_anchor = winter
        next_anchor = spring
        day_index = (day - date(day.year, *winter)).days

    else:
        # Jan 1 through Mar 20
        last_anchor = winter
        next_anchor = spring
        day_index = (
            day - date(day.year - 1, *winter)
        ).days

    last_sunrise, last_sunset = anchors[last_anchor]
    next_sunrise, next_sunset = anchors[next_anchor]

Apply a factor of 1/90 to the date index, and multiply by the difference between next and last anchor sunrise/sunset.

    sunrise = (
        last_sunrise
        + day_index * (1 / 90)
        * (next_sunrise - last_sunrise)
    )

    sunset = (
        last_sunset
        + day_index * (1 / 90)
        * (next_sunset - last_sunset)
    )

    return sunrise, sunset

# alternatively, we can also define span = (date(day.year, *next_anchor) - date(day.year, *last_anchor)).days

Example:

anchors = {
    spring:  (hm(6, 0), hm(18, 0)),   # 6:00 AM, 6:00 PM
    summer:  (hm(5, 0), hm(20, 30)),   # 5:00 AM, 8:30 PM
    fall:  (hm(6, 0), hm(18, 0)),   # 6:00 AM, 6:00 PM
    winter: (hm(7, 0), hm(16, 40)),    # 7:00 AM, 4:40 PM
}

sunrise, sunset = sun_times(
    date(2026, 5, 5),
    anchors)

print(sunrise)
print(sunset)

Exercise 3: ID Code Generator

A system for generating ID numbers containing 4 letters and 5 digits. Each ID is represented by a numbered key in a dictionary containing the current ID, prior IDs, and the characters changed in the most recent generation.

When a new ID is generated, 2 characters are replaced according the following rules.

Rules:

- Each ID must contain exactly 9 characters.
- Each ID must contain exactly 4 letters and 5 digits.
- Exactly 2 characters must be replaced per generation.
- The characters replaced in the previous generation are preserved.
- No previously used ID may be returned.

Replacement logic:

  1. If a number or letter was replaced in the previous ID generation, preserve that character.

  2. For remaining positions:

    • If a number: Sum the digits of the product of the ID's numeric values, and add this number to the target digit.
    • If a letter: Map the letter's position (A-Z) to a corresponding numerical value between 1-26. Add the product of the ID’s numeric values to the target letter, and re-assign to a new letter.
def assign_new_id(members, holder):
    member = members[holder]
    current = member["current_id"]

    used = {
        id_
        for m in members.values()
        for id_ in m["id_history"]
    }

    available = [
        i for i in range(len(current))
        if i not in member["last_changed"]
    ]

    seed = 1
    for c in current:
        if c.isdigit():
            seed *= int(c) + 1

    while True:
        first = available[seed % len(available)]
        rest = [i for i in available if i != first]
        second = rest[seed % len(rest)]
        new = list(current)

        for i in (first, second):
            if current[i].isalpha():
                new[i] = chr(65 + (seed + i) % 26)
                if new[i] == current[i]:
                    new[i] = chr(65 + (seed + i + 1) % 26)
            else:
                new[i] = str((seed + i) % 10)
                if new[i] == current[i]:
                    new[i] = str((seed + i + 1) % 10)

        new = "".join(new)

        if new not in used:
            break

        seed += 1

    member["current_id"] = new
    member["id_history"].append(new)
    member["last_changed"] = [first, second]

    return new

Example:

# Sample members dataset
members = {
    101: {
        "current_id": 'ABCD12345',
        "id_history": ['ABGH12345', 'ABCD12345',]
        "last_changed": [2, 3]  
    },
}

# Run function for member 101
holder = 101
new_id = assign_new_id(members, holder)

print(f"Generated New ID: {new_id}")
print("Updated Member Data:")
print(members[holder])

# Output

Generated New ID: STCD12345
Updated Member Data:
{'current_id': 'STCD12345',
 'id_history': ['ABGH12345', 'ABCD12345', 'STCD12345'],
 'last_changed': [0, 1]}

# The function changes ABCD12345 to STCD12345, replacing A with S and B with T.

Exercise 4: Family pets

I practiced Python during a visit to New York for a family event. A common topic at family gatherings concerns the boarding of everyone's pets, since only some relatives accept pets.

This exercise determines whose pet can tag along, and whose have to be boarded.

people = {
    "Mom":     {"rules": []},
    "Jay":     {"rules": []},
    "Sue":     {"rules": ["cat"]},
    "Steven":  {"rules": []},
    "Shannon": {"rules": []},
    "Arnold":  {"rules": ["dog"]},
}

households = {
    "Mom":          {"residents": ["Mom"],             "accepts_pets": True},
    "Jay_and_Sue":  {"residents": ["Jay", "Sue"],      "accepts_pets": True},
    "Steven":       {"residents": ["Steven"],          "accepts_pets": True},
    "Shannon":      {"residents": ["Shannon"], "accepts_pets": False},
    "Arnold":       {"residents": ["Arnold"],          "accepts_pets": True},
}

pets = {
    "Parker": {"kind": "dog", "owner": "Mom"},
    "Mouse":  {"kind": "cat", "owner": "Mom"},
    "Corgy":  {"kind": "dog", "owner": "Steven"},
    "Wilson": {"kind": "dog", "owner": "Jay"},
    "Collie": {"kind": "dog", "owner": "Shannon"},
}

Now define households, house rules, and boarding, and format the results:

def household_of(person, households):
    for house, info in households.items():
        if person in info["residents"]:
            return house
    return None


def house_rules(house, households, people):
    rule_against = []

    for resident in households[house]["residents"]:
        rule_against.extend(people[resident]["rules"])

    return rule_against


def boarding(pets, visits, households, people):
    result = {}

    for pet, info in pets.items():
        owner = info["owner"]
        kind = info["kind"]

        if owner not in visits:
            result[pet] = ("Stays", f"since {owner} is not traveling")
            continue

        house = household_of(visits[owner], households)

        if kind in house_rules(house, households, people):
            result[pet] = (
                "Boarded",
                f"since {owner} is visiting {house}, who cannot have {kind}s")

        elif households[house]["accepts_pets"]:
            result[pet] = (
                "Comes",
                f"since {owner} is visiting {house}, who welcomes {kind}s")

        else:
            result[pet] = (
                "Boarded",
                f"since {owner} is visiting {house}, who does not take {kind}s")
                
    return result

Example: Mom visiting Aunt Sue

  visits = {"Mom": "Sue"}

for pet, (boards, why) in boarding(
    pets, visits, households, people
    ).items():
    print(pet, boards, why)

# Result: 
Parker Comes since Mom is visiting Jay_and_Sue, who welcomes dogs
Mouse Boarded since Mom is visiting Jay_and_Sue, who cannot have cats
Corgy Stays since Steven is not traveling
Wilson Stays since Jay is not traveling
Collie Stays since Shannon is not traveling

Briefly, the Ratio Method.

def ratio_method(incident_count, population, total_damages, gdp_per_capita,
                 sv1: int, sv2: str, th: str, lc1: int, lc2: int):

    return {
        # Frequency (F): how often the harm occurs, incidents relative to
        # the exposed population.
        "Frequency": incident_count / population,

        # Average Damages (AD): the typical size of harm per incident,
        # compared against economic output (GDP per capita). Corresponds to what
        # Gifford refers to as "severity."
        "Average_Damages": total_damages / gdp_per_capita,

        # Social Value 1 (SV1): the economic value that the activity adds —
        # its productive benefit to society.
        "SV1": int(sv1),

        # Social Value 2 (SV2): the cultural inclination toward the
        # activity — its value beyond pure economics.
        "SV2": str(sv2),

        # Type of Harm (TH): a classification across the six dimensions in
        # TYPE_OF_HARM below (type of injury, defendant's role, physical
        # agent, onset, location, reason). Every axis is categorical — none
        # is quantitative. 
        "Type_Harm": str(th),

        # Litigation Costs 1 (LC1): the cost structure of bringing a claim —
        # information costs versus claim costs (Landes & Posner).
        "LC1": int(lc1),

        # Litigation Costs 2 (LC2): the difficulty
        # of proving liability (Gifford factor 3).
        "LC2": int(lc2)
        # LC2 can be a string (e.g., "low", "moderate", "high") or an integer (e.g., 1-10), depending on how we define it.
    }

# Type of Harm (TH): the article's "mechanisms of action" classification. 
#Each harm is characterized across SIX dimensions, each with its own set of values. 
# A real harm is one value drawn from each axis.
TYPE_OF_HARM = {
    "type_of_injury":     ["Physical/Medical", "Financial", "Environmental", "Rights Violation"],
    "defendants_role":    ["Direct Action", "Product Developer", "Failure of Oversight", "Vicarious/Passive"],
    "physical_agent":     ["Defendant", "Product/Device", "Third-Party(s)", "Non-Product Physical Object"],
    "onset_of_injury":    ["Immediate/Imminent", "Definite Future", "Prolonged", "Uncertain"],
    "location_of_injury": ["Proximate Zone", "Spanning Zone", "Sporadic", "Intangible/Internet"],
    "reason_for_injury":  ["Malice", "Negligence", "Recklessness", "Pure Accident"],
}


## Thanks for reading!

About

Personally developed Python practice exercises covering functions and small data-oriented problems.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors