Applied Programming/Dictionaries and Sets/Python3

regex_dictionaries.pyEdit

This is the regex way of using dictionaries.

"""This program demonstrates file, list, and dictionary processing.

It creates a temporary file, adds data to the file, and reads the file
into a list of dictionaries. It then provides a menu of options for displaying 
and searching the file data.

It will not run if the file already exists.

Input:
    None

Output:
    A temporary file and file contents.

References:
    https://www.tutorialspoint.com/python/python_tuples.htm

"""

import os
import re
import sys

def create_file(filename):
    """Creates filename and adds temperature data to the file.

    Args:
        filename (string): Filename to create.

    Returns:
        None

    """
    with open(filename, 'w') as file:
        file.write('"C","F"\n')
        for c in range(0, 101, 10):
            f = c * 9 / 5 + 32
            file.write(f"{c:.2} {f:.2}\n")


def read_file(filename):
    """Reads filename and returns a list of temperature tuples.

    Args:
        filename (string): Filename to open and read.

    Returns:
        A list of temperature tuples.
        
    Raises:
        ValueError: Invalid header format.
        ValueError: Invalid record format.
        ValueError: No data found.

    """
    with open(filename, 'r') as file:
        line = file.readline()
        if line.strip() != '"C","F"':
            raise ValueError(f"Invalid header format found in {filename}: {line}")
            
        temperatures = []
        fields = ['C', 'F']
        for line in file:
            if 'C' in line:
                continue
            record = re.findall('"(.*?)"', line)
            if len(record) != len(fields):
                raise ValueError(f"Invalid record format found in {filename}: {line}")
                
            temperature = {}
            for i in range(len(fields)):
                temperature[fields[i]] = float(record[i])
            temperatures.append(temperature)
            
    if len(temperatures) == 0:
        raise ValueError(f"No data found in {filename}")
    return temperatures


def delete_file(filename):
    """Deletes filename.

    Args:
        filename (string): Filename to delete.

    Returns:
        None

    """
    os.remove(filename)


def get_choice():
    """Displays menu and gets choice.

    Args:
        None

    Returns:
        choice (int) or None

    """
    while True:
        try:
            print("Select from the following options or press <Enter> to quit:")
            print("1. Display table sorted by Celsius temperature.")
            print("2. Display table sorted by Fahrenheit temperature.")
            print("3. Search for Celsius temperature.")
            print("4. Search for Fahrenheit temperature.")
            choice = input()
            choice = int(choice)
            if 1 <= choice <= 4:
                print()
                return choice
            print(f"{choice} is not a valid choice.\n")
        except ValueError:
            if choice == "":
                return None
            print(f"{choice} is not a valid choice.\n")


def display_temperatures(temperatures, scale):
    """Displays temperatures sorted in scale order.
    
    Args:
        temperatures (list of Celsius, Fahrenheit tuples)
        scale (string): "Celsius" or "Fahrenheit"

    Returns:
        None

    """
    if scale == "Celsius":
        data = sorted(temperatures, key=lambda record: record['C'])
        fields = ['C', 'F']
    elif scale == "Fahrenheit":
        data = sorted(temperatures, key=lambda record: record['F'])
        fields = ['F', 'C']
    else:
        raise ValueError("scale must be Celsius or Fahrenheit")
    print(f"{fields[0]} \t {fields[1]})
    for record in data:
        print(f"{record[fields[0]]} \t {record[fields[1]]}")
    print()


def get_temperature(scale):
    """Gets Fahrenheit or Celsius temperature.
    
    Args:
        scale (string): "Celsius" or "Fahrenheit"

    Returns:
        temperature (float) or None

    """
    assert scale == "Celsius" or scale == "Fahrenheit"
    while True:
        try:
            print("Enter %s temperature:" % scale)
            temperature = input()
            temperature = float(temperature)
            print()
            return temperature
        except ValueError:
            print("%s is not a valid %s temperature\n" %
                (temperature, scale))
            return None


def search_temperatures(temperatures, scale):
    """Search temperatures for a scale temperature and display the nearest match.
    
    Args:
        temperatures (list of Celsius, Fahrenheit tuples)
        scale (string): "Celsius" or "Fahrenheit"

    Returns:
        None

    Raises:
        ValueError: If temperatures list is empty
        ValueError: If scale is invalid
        
    """
    if len(temperatures) <= 0:
        raise ValueError("temperatures list is empty")
    
    temperature = get_temperature(scale)
    if temperature == None:
        return

    if scale == "Celsius":
        search_element = 'C'
        display_element = 'F'
        other_scale = "Fahrenheit"
    elif scale == "Fahrenheit":
        search_element = 'F'
        display_element = 'C'
        other_scale = "Celsius"
    else:
        raise ValueError("scale must be Celsius or Fahrenheit")
        
    data = sorted(temperatures, key=lambda record: record[search_element])
    last = data[0]
    for record in data:
        if temperature < record[search_element]:
            break
        last = record

    if temperature < last[search_element]:
        print(f"{temperature:.2}° {scale} is less than {last[display_element]:.2}° {other_scale}\n")
    elif temperature == last[search_element]:
        print(f"{temperature:.2}° {scale} is {last[display_element]:.2}° {other_scale}\n")
    elif temperature > record[search_element]:
        print(f"{temperature:.2}° {scale} is greater than {last[display_element]:.2}° {other_scale}\n")
    else:
        print(f"{temperature:.2}° {scale} is between {last[display_element]:.2}° {other_scale} and {record[display_element]:.2 
             {other_scale}\n")

def main():
    """Runs the main program logic."""

    try:
        filename = "~temperatures.txt"

        if os.path.isfile(filename):
            print(f"File '{filename}' already exists.")
            exit(1)

        create_file(filename)
        temperatures = read_file(filename)
        delete_file(filename)
        
        while True:
            choice = get_choice()
            if choice == None:
                break
            elif choice == 1:
                display_temperatures(temperatures, "Celsius")
            elif choice == 2:
                display_temperatures(temperatures, "Fahrenheit")
            elif choice == 3:
                search_temperatures(temperatures, "Celsius")
            elif choice == 4:
                search_temperatures(temperatures, "Fahrenheit")
            else:
                raise ValueError("Invalid option selected")
    except:
        print("Unexpected error.")
        print("Error:", sys.exc_info()[1])
        print("File: ", sys.exc_info()[2].tb_frame.f_code.co_filename) 
        print("Line: ", sys.exc_info()[2].tb_lineno)


main()

csv_dictionaries.pyEdit

"""This program demonstrates file, list, and dictionary processing.

It creates a temporary file, adds data to the file, and reads the file
into a list of dictionaries. It then provides a menu of options for displaying
and searching the file data.

It will not run if the file already exists.

Input:
    None

Output:
    A temporary file and file contents.

References:
    https://www.tutorialspoint.com/python/python_tuples.htm

"""

import os
import csv
import sys


def create_file(filename):
    """Creates filename and adds temperature data to the file.

    Args:
        filename (string): Filename to create.

    Returns:
        None

    """
    with open(filename, 'w') as file:
        file.write('"C","F"\n')
        for c in range(0, 101, 10):
            f = c * 9 / 5 + 32
            file.write(f'"{c:.1f}","{f:.1f}"\n')


def read_file(filename):
    """Reads filename and returns a list of temperature dictionaries.

    Args:
        filename (string): Filename to open and read.

    Returns:
        A list of temperature dictionaries.

    Raises:
        ValueError: Invalid header format.
        ValueError: Invalid record format.
        ValueError: No data found.

    """
    with open(filename, 'r') as file:
        temperatures = []
        reader = csv.DictReader(file)
        for line in reader:
            temperatures.append(dict(line))
    if len(temperatures) == 0:
        raise ValueError(f"No data found in {filename}")
    return temperatures


def delete_file(filename):
    """Deletes filename.

    Args:
        filename (string): Filename to delete.

    Returns:
        None

    """
    os.remove(filename)


def get_choice():
    """Displays menu and gets choice.

    Args:
        None

    Returns:
        choice (int) or None

    """
    while True:
        try:
            print("Select from the following options or press <Enter> to" +
                  " quit:")
            print("1. Display table sorted by Celsius temperature.")
            print("2. Display table sorted by Fahrenheit temperature.")
            print("3. Search for Celsius temperature.")
            print("4. Search for Fahrenheit temperature.")
            choice = input()
            choice = int(choice)
            if 1 <= choice <= 4:
                print()
                return choice
            print(f"{choice} is not a valid choice.\n")
        except ValueError:
            if choice == "":
                return None
            print(f"{choice} is not a valid choice.\n")


def display_temperatures(temperatures, scale):
    """Displays temperatures sorted in scale order.

    Args:
        temperatures (list of Celsius, Fahrenheit tuples)
        scale (string): "Celsius" or "Fahrenheit"

    Returns:
        None

    """
    if scale == "Celsius":
        data = sorted(temperatures, key=lambda record: float(record['C']))
        fields = ['C', 'F']
    elif scale == "Fahrenheit":
        data = sorted(temperatures, key=lambda record: float(record['F']))
        fields = ['F', 'C']
    else:
        raise ValueError("scale must be Celsius or Fahrenheit")
    
    print(f"{fields[0]:10}{fields[1]:10}")
    for record in data:
        print(f"{record[fields[0]]:10}{record[fields[1]]:10}")
    print()


def get_temperature(scale):
    """Gets Fahrenheit or Celsius temperature.

    Args:
        scale (string): "Celsius" or "Fahrenheit"

    Returns:
        temperature (float) or None

    """
    assert scale == "Celsius" or scale == "Fahrenheit"
    while True:
        try:
            print(f"Enter {scale} temperature:")
            temperature = input()
            temperature = float(temperature)
            print()
            return temperature
        except ValueError:
            print(f"{temperature} is not a valid {scale} temperature\n")
            return None


def search_temperatures(temperatures, scale):
    """Search temperatures for a scale temperature and display the nearest match.

    Args:
        temperatures (list of Celsius, Fahrenheit tuples)
        scale (string): "Celsius" or "Fahrenheit"

    Returns:
        None

    Raises:
        ValueError: If temperatures list is empty
        ValueError: If scale is invalid

    """
    if len(temperatures) <= 0:
        raise ValueError("temperatures list is empty")

    temperature = get_temperature(scale)
    if temperature is None:
        return

    if scale == "Celsius":
        search_element = 'C'
        display_element = 'F'
        other_scale = "Fahrenheit"
    elif scale == "Fahrenheit":
        search_element = 'F'
        display_element = 'C'
        other_scale = "Celsius"
    else:
        raise ValueError("scale must be Celsius or Fahrenheit")

    data = sorted(temperatures, key=lambda record:
                  float(record[search_element]))
    last = data[0]
    for record in data:
        if temperature < float(record[search_element]):
            break
        last = record

    if temperature < float(last[search_element]):
        print(f'{temperature}° {scale} is less than' +
              f' {last[display_element]}° {other_scale}.')
    elif temperature == float(last[search_element]):
        print(f'{temperature}° {scale} is {last[display_element]}°' +
              f' {other_scale}.')
    elif temperature > float(last[search_element]):
        print(f'{temperature}° {scale} is greater than' +
              f' {last[display_element]}° {other_scale}.')
    else:
        print(f'{temperature}° {scale} is between {last[display_element]}°' +
              f' {other_scale} and {record[display_element]}° {other_scale}.')


def main():
    """Runs the main program logic."""
    try:

        filename = "~temperatures.txt"

        if os.path.isfile(filename):
            print("File '%s' already exists." % filename)
            os.remove(filename)

        create_file(filename)
        temperatures = read_file(filename)
        delete_file(filename)

        while True:
            choice = get_choice()
            if choice is None:
                break
            elif choice == 1:
                display_temperatures(temperatures, "Celsius")
            elif choice == 2:
                display_temperatures(temperatures, "Fahrenheit")
            elif choice == 3:
                search_temperatures(temperatures, "Celsius")
            elif choice == 4:
                search_temperatures(temperatures, "Fahrenheit")
            else:
                raise ValueError("Invalid option selected")
    except:
        os.remove(filename)
        print("Unexpected error.")
        print("Error:", sys.exc_info()[1])
        print("File: ", sys.exc_info()[2].tb_frame.f_code.co_filename)
        print("Line: ", sys.exc_info()[2].tb_lineno)


main()

Try ItEdit

Copy and paste the code above into one of the following free online development environments or use your own Python3 compiler / interpreter / IDE.

See AlsoEdit