solution_222a.py

#!/usr/bin/python3
# ====================================================================
# stack (LIFO queue)
#
# Notes:
# 1. queue.Queue and collections.deque serve different purposes.
#    queue.Queue is intended for allowing different threads to
#    communicate using queued messages/data, whereas collections.deque
#    is simply intended as a data structure.
# 2. Deque (Doubly Ended Queue)
# 3. TOS = Top Of Stack
#
# Useful URL: www.geeksforgeeks.org/deque-in-python/
# ====================================================================

from collections import deque

# --------------------------------------------------------------------
# --- LIFO queue class
# --------------------------------------------------------------------

class Stack:

    # initialize stack  
    def __init__(self):
        self.stack = deque()

    # pop from TOS           
    def pop(self) -> any:
        if len(self.stack) == 0: return None
        return self.stack.pop()

    # push onto TOS        
    def push(self,e:any):
        self.stack.append(e)
        return

    # modify TOS
    def modify_tos(self,e:any):
        if len(self.stack) == 0: return False
        self.stack[-1] = e
        return True
    
    # is stack empty?
    def is_empty(self):
        if len(self.stack) == 0: return True
        return False

    # return copy of TOS        
    def tos(self):
        if len(self.stack) == 0: return None 
        return self.stack[-1]

    # length of stack
    # (return the number elements)
    def length(self):
        return len(self.stack)

    # clear (empty) stack
    # (return the count of elements removed)
    def clear(self):
        i = 0
        for _ in range(len(self.stack)):
            self.stack.pop()
            i += 1
        return i

    # return stack as a list of token
    def as_list(self):
        return list(self.stack)

# --------------------------------------------------------------------
# ---- main
# --------------------------------------------------------------------

if __name__ == '__main__':

    import user_interface as ui

    # ---- user enter stack element value

    def enter_stack_element():
        e = ui.get_user_input('Enter stack element: ')
        if not e: return None    # empty string
        return e

    menu = '''
------ Test collections.deque as LIFO Stack ------
--------------------------------------------------
Option  Description
------  ------------------------------------------
  1     push onto stack
  2     pop from stack (element removed)
  3     top of stack   (element not removed)
  4     modify top of stack
  5     is stack empty?
  6     stack length
  7     clear stack
  8     display stack as list
  9     display stack as string'''
    print(menu)

    stack = Stack()
    
    while True:

        # ---- ask the user to select option

        print()
        s = ui.get_user_input('Enter option: ')

        if not s: break

        tf,opt = ui.is_integer(s)

        if not tf:
            print()
            print(f'Illegal option ({s}) - try again')
            continue

        if opt == 0:        # exit program
            break

        if opt == 1:         # push onto stack
            e = enter_stack_element()
            if e is not None: stack.push(e)
            continue

        if opt == 2:         # pop from stack
            print(f'{stack.pop()} (poped from TOS)')
            continue

        if opt == 3:         # copy of top of stack
            print(f'{stack.tos()} (copied from TOS)')
            continue

        if opt == 4:         # modify top of stack
            e = enter_stack_element()
            if e is not None: print(stack.modify_tos(e))
            continue

        if opt == 5:         # is stack empty
            print(stack.is_empty())
            continue

        if opt == 6:         # stack length
            print(stack.length())
            continue

        if opt == 7:         # clear (empty) stack
            count = stack.clear()
            continue

        if opt == 8:         # stack as list
            print(stack.as_list())
            continue

        if opt == 9:         # stack as string
            print(','.join(stack.as_list()))
            continue

        print()
        print(f'Unknown option ({opt}) - try again')