Python Code Exercises

GitHub repo link - https://github.com/senaonp/code-demos-python
Exercise Code
HashMap
an implementation of a HashMap data structure with specified properties and methods


HashMap - (properties: map, size)

a HashMap has a map Array of a specified size

HashMap methods:
- getters (properties: get_map, get_size)
- metadata getters (properties: get_available_space, get_used_space)
- hash
- compress
- add_item
- get_item
- remove_item

solution screenshot
class HashMap:
  def __init__(self, size=0):
    self.map = [None]*size
    self.size = size
    print("initializing a HashMap with size ({0})".format(size))

  # hash function
  def hash(self, key, collisions=0):
    r = 0
    for c in key:
      r += ord(c)
    return r + collisions

  # compression function
  def compress(self, value):
    return value % self.size

  # getters
  def get_map(self):
    return self.map
  def get_size(self):
    return self.size

  # metadata getters
  def get_available_space(self):
    return len([a for a in self.map if a is None])
  def get_used_space(self):
    return len([a for a in self.map if a is not None])

  # add an item to the HashMap
  def add_item(self, key, value):
    hash_index = self.compress(self.hash(key))
    resolved = self.map[hash_index]
    collisions = 0
    if resolved is None:
      self.map[hash_index] = [key, value]
      print("now added ({0}, {1}) to HashMap under the resolved index {2}".format(key, value, hash_index))
      return
    if resolved[0] == key:
      self.map[hash_index][1] = value
      print("existing key encountered, overwriting to use ({0}, {1}) to HashMap under the resolved index {2}".format(key, value, hash_index))
      return
    collisions += 1
    while (collisions <= self.size):
      print("index collision encountered at {0}: checking next index...".format(hash_index))
      hash_index = self.compress(self.hash(key, collisions))
      resolved = self.map[hash_index]
      if resolved is None:
        self.map[hash_index] = [key, value]
        print("now added ({0}, {1}) to HashMap under the resolved index {2}".format(key, value, hash_index))
        return
      if resolved[0] == key:
        self.map[hash_index][1] = value
        print("existing key encountered in the resolved index {0}, overwriting to use ({1}, {2})".format(hash_index, key, value))
        return
      collisions += 1
    print("cannot find an available index to store ({0}, {1}) in the HashMap; adding capacity to HashMap...".format(key, value))
    self.map.insert(hash_index, [key, value])
    self.size += 1
    print("now inserted ({0}, {1}) at the index {2}; HashMap size is now {3}".format(key, value, hash_index, self.size))
    return

  # retrieve an item from the HashMap
  def get_item(self, key):
    hash_index = self.compress(self.hash(key))
    resolved = self.map[hash_index]
    collisions = 0
    if resolved is None:
      print("cannot find value for the given key ({0})".format(key))
      return None
    if resolved[0] == key:
      print("found value ({0}) for the key ({1})".format(resolved[1], key))
      return resolved[1]
    collisions += 1
    while (collisions <= self.size):
      print("key not found at index ({0}); checking next available index...".format(hash_index))
      hash_index = self.compress(self.hash(key, collisions))
      resolved = self.map[hash_index]
      if resolved is None:
        print("cannot find value for the given key ({0})".format(key))
        return None
      if resolved[0] == key:
        print("found value ({0}) for the key ({1})".format(resolved[1], key))
        return resolved[1]
      collisions += 1
    print("cannot find value for the given key ({0})".format(key))
    return

  # remove a (key, value) pair given a key from the HashMap
  def remove_item(self, key):
    hash_index = self.compress(self.hash(key))
    resolved = self.map[hash_index]
    collisions = 0
    if resolved is None:
      print("cannot find value for the given key ({0}); skipping item removal".format(key))
      return None
    if resolved[0] == key:
      self.map[hash_index] = None
      print("removed key, value pair ({0}, {1}) from the HashMap".format(key, resolved[1]))
      return resolved[1]
    collisions += 1
    while (collisions <= self.size):
      print("key not found at index ({0}); checking next available index...".format(hash_index))
      hash_index = self.compress(self.hash(key, collisions))
      resolved = self.map[hash_index]
      if resolved is None:
        print("cannot find value for the given key ({0}); skipping item removal".format(key))
        return None
      if resolved[0] == key:
        self.map[hash_index] = None
        print("removed key, value pair ({0}, {1}) from the HashMap".format(key, resolved[1]))
        return resolved[1]
      collisions += 1
    print("cannot find value for the given key ({0}); skipping item removal".format(key))
    return
LinkedList
an implementation of a LinkedList linear data structure with specified properties and methods


Node - (properties: value, next)

a Node can store a value and reference another Node

Node methods:
- getters (properties: value, next)
- setters (properties: value, next)


LinkedList - (properties: head, tail, value)

a LinkedList has a head Node (initialized with a value) and a tail Node

LinkedList methods:
- getters (properties: head, tail)
- setters (properties: head, tail)
- add_node
- remove_node
- get_nth_node
- get_node
- print_nodes
- reverse


LinkedList Queue (FIFO) methods:
- queue
- dequeue


LinkedList Stack (FILO) methods:
- stack
- destack

example screenshot
class Node:
  def __init__(self, value, next=None):
    self.value = value
    self.next = next

  # getters
  def get_value(self):
    return self.value
  def get_next(self):
    return self.next

  # setters
  def set_value(self, value):
    self.value = value
  def set_next(self, next):
    self.next = next



class LinkedList:
  # initialize LinkedList with one node
  def __init__(self, value=None):
    self.head = Node(value)
    self.tail = self.head
    print("initialized LinkedList with starting head node {0}".format(self.head))

  # get the head (root) node
  def get_head(self):
    return self.head
  # get the tail (ending) node
  def get_tail(self):
    return self.tail

  # set the head (root) node
  def set_head(self, node):
    self.head = node
  # set the tail (ending) node
  def set_tail(self, node):
    self.tail = node

  # add a node to the LinkedList
  def add_node(self, value, location='head'):
    node_to_add = Node(value)
    if location == 'head':
      node_to_add.set_next(self.head)
      self.head = node_to_add
      print("linked node {0} to {1}".format(node_to_add, self.head.get_next()))
      return
    if location == 'tail':
      current_node = self.head
      while(current_node.get_next() is not None):
        current_node = current_node.get_next()
      current_node.set_next(node_to_add)
      self.tail = node_to_add
      print("linked node {0} to {1}".format(current_node, self.tail))
      return
    print('invalid location parameter - {0}; it should either be "head" or "tail"'.format(location))

  # remove a node to the LinkedList
  def remove_node(self, location='head'):
    if location == 'head':
      current_node = self.head
      self.head = current_node.get_next()
      current_node.set_next(None)
      print("removed head node; setting head node to {0}".format(self.head))
      return
    if location == 'tail':
      current_node = self.head
      while current_node is not None:
        if current_node.get_next().get_next() == None:
          break
        current_node = current_node.get_next()
      self.tail = current_node
      current_node.set_next(None)
      print("removed tail node; setting tail node to {0}".format(self.tail))
      return
    print('invalid location parameter - {0}; it should either be "head" or "tail"'.format(location))

  # get the nth node starting from the head node
  def get_nth_node(self, n):
    current = self.get_head()
    counter = 0
    while(current is not None):
      if (counter == n):
        print("found node {0} at location {1}".format(current, n))
        return current
      current = current.get_next()
      counter += 1
    print("could not find node at location {0} in LinkedList".format(n))
    return

  # get the node containing a specified value
  def get_node(self, value):
    current = self.get_head()
    while(current is not None):
      if (current.value == value):
        print("found node {0} with value {1}".format(current, value))
        return current
      current = current.get_next()
    print("could not find node with value {0} in the LinkedList".format(value))
    return

  # print all the nodes and their respective values
  def print_nodes(self):
    current = self.get_head()
    while(current is not None):
      print("node {0} | value {1}".format(current, current.value))
      current = current.get_next()
    return

  # reverse the list (mutating)
  def reverse(self):
    current_node = self.get_head()
    self.set_tail(current_node)
    next_node = current_node.get_next()
    previous_node = None
    while next_node is not None:
      next_node = current_node.get_next()
      current_node.set_next(previous_node)
      print("setting node {0} to reference {1}".format(current_node, previous_node))
      previous_node = current_node
      current_node = next_node
    self.set_head(previous_node)
    print("reversed LinkedList - head is {0} | tail is {1}".format(self.head, self.tail))

  # ----------------------------------------------
  # implement Queue (FIFO) using LinkedList
  # ----------------------------------------------

  # queue nodes
  def queue(self, value=None, location='head'):
    node_to_add = Node(value)
    if location == 'head':
      node_to_add.set_next(self.head)
      self.head = node_to_add
      print("queue-ing node {0} from head Queue; setting head node to {1}".format(node_to_add, self.head))
      return
    if location == 'tail':
      self.tail.next = node_to_add
      self.tail = self.tail.next
      print("queue-ing node {0} from tail Queue; setting tail node to {1}".format(node_to_add, self.tail))
      return
    print('invalid location parameter - {0}; it should either be "head" or "tail"'.format(location))

  # dequeue nodes
  def dequeue(self, location='head'):
    if location == 'head':
      current_node = self.head
      while(current_node is not None):
        if current_node.get_next().get_next() == None:
          break
        current_node = current_node.get_next()
      self.tail = current_node
      self.tail.set_next(None)
      print("dequeue-ing node from head Queue; setting tail node to {0}".format(self.tail))
      return
    if location == 'tail':
      current_node = self.head
      next_node = current_node.get_next()
      self.head = next_node
      current_node.set_next(None)
      print("dequeue-ing node from tail Queue; setting head node to {0}".format(self.head))
      return
    print('invalid location parameter - {0}; it should either be "head" or "tail"'.format(location))

  # ----------------------------------------------
  # implement Stack (FILO) using LinkedList
  # ----------------------------------------------

  # stack nodes
  def stack(self, value=None, location='head'):
    node_to_add = Node(value)
    if location == 'head':
      node_to_add.set_next(self.head)
      self.head = node_to_add
      print("queue-ing node {0} from head Stack; setting head node to {1}".format(node_to_add, self.head))
      return
    if location == 'tail':
      self.tail.next = node_to_add
      self.tail = self.tail.next
      print("queue-ing node {0} from tail Stack; setting tail node to {1}".format(node_to_add, self.tail))
      return
    print('invalid location parameter - {0}; it should either be "head" or "tail"'.format(location))

  # destack nodes
  def destack(self, location='head'):
    if location == 'head':
      current_node = self.head
      self.head = current_node.get_next()
      current_node.set_next(None)
      print("destack-ing node from head Stack; setting head node to {0}".format(self.head))
      return
    if location == 'tail':
      current_node = self.head
      while (current_node.get_next() is not None):
        if current_node.get_next().get_next() == None:
          break
        current_node = current_node.get_next()
      self.tail = current_node
      self.tail.set_next(None)
      print("destack-ing node from tail Stack; setting tail node to {0}".format(self.tail))
      return
    print('invalid location parameter - {0}; it should either be "head" or "tail"'.format(location))
LRUcache
an implementation of a LRUcache data structure


LRUcache - (properties: capacity, cache)

LRUcache methods:
- get
- set

example screenshot
class LRUcache:
  def __init__(self, capacity):
    self.capacity = capacity
    self.cache = []

  def get(self, key):
    keys = [i[0] for i in self.cache]
    if key in keys:
      k = keys.index(key)
      print(f"item with key ({key}) found with value ({self.cache[k][1]})")
      return self.cache[k][1]
    print(f"cannot find value for item with key: ({key})")
    return -1

  def set(self, key, value):
    keys = [i[0] for i in self.cache]
    if key in keys:
      k = keys.index(key)
      del self.cache[k]
    self.cache.append([key, value])
    if len(self.cache) > self.capacity:
      self.cache.pop(0)
    return

  def __repr__(self):
    return str(self.cache)
BinaryTree
an implementation of a BinaryTree data structure with specified properties and methods


Node - (properties: value, left, right)

a Node can store a value and reference at most two other Nodes (left and right)

Node methods:
- setters (properties: value, left, right)


BinaryTree - (properties: value)

a BinaryTree has a root node (initialized with a value)

BinaryTree methods:
- getters (properties: root)
- add_node
- get_node
- print_nodes
- invert

example screenshot
class Node:
  def __init__(self, value, left=None, right=None):
    self.value = value
    self.left = left
    self.right = right

  # setters
  def set_value(self, value):
    self.value = value
  def set_left(self, left):
    self.left = left
  def set_right(self, right):
    self.right = right



class BinaryTree:
  # initialize tree with a root node
  def __init__(self, value=None):
    self.root = Node(value)
    print("initializing binary tree with root {0}".format(self.root))

  # getter [root node]
  def get_root(self):
    return self.root

  # add node to the tree
  def add_node(self, value):
    node_to_add = Node(value)
    nodes_to_search = [self.root]
    while (len(nodes_to_search) > 0):
      current_node = nodes_to_search.pop(0)
      for child in [current_node.left, current_node.right]:
        if current_node.left is None:
          current_node.set_left(node_to_add)
          print("adding node {0} as left child of {1}".format(node_to_add, current_node))
          return
        if current_node.right is None:
          current_node.set_right(node_to_add)
          print("adding node {0} as right child of {1}".format(node_to_add, current_node))
          return
        nodes_to_search.append(child)

  # get node with specified value
  def get_node(self, value):
    nodes_to_search = [self.root]
    while (len(nodes_to_search) > 0):
      current_node = nodes_to_search.pop(0)
      if current_node.value == value:
        print("found node {0} which contains value {1}".format(current_node, current_node.value))
        return current_node
      for child in [current_node.left, current_node.right]:
        if child is not None:
          nodes_to_search.append(child)
    print("cannot find node with value {0}".format(value))
    return None

  # print all the nodes in the tree
  def print_nodes(self):
    nodes_to_search = [self.root]
    while (len(nodes_to_search) > 0):
      current_node = nodes_to_search.pop(0)
      print("found node {0} with value {1}".format(current_node, current_node.value))
      for child in [current_node.left, current_node.right]:
        if child is not None:
          nodes_to_search.append(child)

  # invert the tree
  def invert(self):
    parent_nodes = [self.root]
    while(len(parent_nodes) > 0):
      parent_node = parent_nodes.pop(0)
      tmp_left = parent_node.left
      parent_node.set_left(parent_node.right)
      parent_node.set_right(tmp_left)
      print("switching {0} with {1}".format(parent_node.left, parent_node.right))
      for child in [parent_node.left, parent_node.right]:
        if child is not None:
          parent_nodes.append(child)
Binary Search
Given a value 's' to find in an ordered list 'ls[]':

- Perform a binary search on 'ls[]'.
- Return the index of 's' in 'ls[]'
- If 'ls[]' doesn't contain 's' return None

solution screenshot
def binary_search(ls=[], s=None):
  i = 0
  while(True):
    if len(ls) < 3:
      if ls[0] == s:
        return i
      if ls[1] == s:
        return i+1
      return None

    m = len(ls)//2
    if ls[0] <= s < ls[m]:
      ls = ls[0:m]
    else:
      ls = ls[m::]
      i+=m
Item Frequency
Given a list 'i[]':

- Return a dictionary containing key value pairs as {i[n], # of occurences of i[n]}

solution screenshot
def item_frequency(i):
  a = {}
  for b in i:
    a[str(b)] = 1 if str(b) not in a.keys() else a.get(str(b))+1
  return a
Sorting Algorithm
Given an unsorted list 'ls[]', use an algorithm to sort 'ls[]'

- Return the sorted list of 'ls[]'

solution screenshot
def sort_list(ls):
  b = 1
  while b:
    b = 0
    for a in range(0,len(ls)-1):
      if ls[a] > ls[a+1]:
        ls[a], ls[a+1] = ls[a+1], ls[a]
        b = 1
  return ls
Sorting Algorithm - Variation 2
Given an unsorted list 'arr[]', use an algorithm to sort 'arr[]'

- Return the sorted list of 'arr[]'

solution screenshot
def sort_var2(arr):
  c = 0
  while(c != len(arr)-1):
    if (arr[c] > arr[c+1]):
      arr[c], arr[c+1] = arr[c+1], arr[c]
      c = 0
    else:
      c += 1
  return arr
Removing duplicates
Given an unsorted list 'arr[]', remove duplicate items in 'arr[]'

- Remove any duplicate items within arr[] and return the list object.

solution screenshot
def remove_duplicates(arr):
  arr = sort_list(arr)
  for i in range(len(arr)-1,0,-1):
    if arr[i] == arr[i-1]:
      del arr[i]
  return arr
Removing duplicates (no sorting)

Given an unsorted list 'arr[]', remove duplicate items in 'arr[]'

- Without sorting the list, remove any duplicate items within arr[] and return the list object.

solution screenshot
def remove_duplicates_no_sort(arr):
  for a in range(len(arr)):
    for b in range(len(arr)-1,a,-1):
      if arr[a] == arr[b]:
        del arr[b]
  return arr
Partition List
Given a list 'ls[]' and int 's':

- Partition 'ls[]' into 's' parts (e.g. divide a list of 100 items into 5 parts)
- If the list cannot be cleanly divided evenly (i.e. len(ls)%s != 0), distribute the remaining items into the partitions.
- Preserve the ordering of the list.
- Return a list containing the partitions of 'ls[]'.

solution screenshot
def partition_list(ls=[], s=1):
  r, i, n, z = [], 0, len(ls)//s, len(ls)%s
  for a in range(0,s):
    r.append(ls[i:i+n])
    i+=n
    if z != 0:
      r[a].append(ls[i])
      z, i = z-1, i+1
  return r
Reverse List
Given a list 'li[]'

- Return the list object containing the elements of li[] in reverse order

solution screenshot
def reverse_list(li):
  i, h = len(li)-1, len(li)//2
  for j in range(h):
    li[j], li[i-j] = li[i-j], li[j]
  return li
Merge Lists by Index

Given two lists 'a1[]', 'a2[]' and index 'i':

- Add the elements of a1 into a2 at index i
- Return the updated list a2
- If the index is invalid return None

solution screenshot
def merge_lists(a1,a2,i):
  if i <= len(a2) and i >= 0:
    b = 0
    for a in a1:
      a2.insert(i+b,a)
      b+=1
    return a2
  return None
Multithreading Partitions
Use multithreading to run a function across multiple lists:

- Start a thread for each partition 'p' which calls a function 'cube_numbers()'
- Let cube_numbers() print the cube of each element in 'p'

solution screenshot
import threading

def cube_numbers(ls):
  for a in ls:
    print(str(a) + "^3 = " + str(a**3))

...
def partition_list(ls=[], s=1):
...

# returns 10 partitions of the 100 element list
pl = partition_list(ls=[1,2,3,4,5,6,7,8,9,10 ... 100], s=10)

# start threads to process each partition
for p in pl:
  a = threading.Thread(target=cube_numbers, args=(p,))
  a.start()
Recursion: Reverse List
Given a list "i[]":

- Recursively reverse the list items and return the reversed list

solution screenshot
def recursive_reverse_list(i):
  r = []
  if len(i) <= 1:
    return i
  r = [i[len(i)-1]] + recursive_reverse_list(i[1:len(i)-1]) + [i[0]]
  return r
Recursion: Sort List
Given a list of numbers "i[]":

- Recursively sort the list items and return the sorted list

solution screenshot
def recursive_sort_list(i):
  r = []
  if len(i) <= 1:
    return i
  for j in range(len(i)):
    if i[j] < i[0]:
      i[0], i[j] = i[j], i[0]
  r += [i[0]] + recursive_sort_list(i[1:])
  return r
Recursion: Sort List (Two-tailed)
Given a list of numbers "i[]":

- Recursively sort the list items and return the sorted list

solution screenshot
def recursive_sort_list_two_tailed(i):
  r = []
  if len(i) <= 1:
    return i
  for j in range(len(i)):
    if i[j] < i[0]:
      i[0], i[j] = i[j], i[0]
    if i[j] > i[-1]:
      i[-1], i[j] = i[j], i[-1]
  r += [i[0]] + recursive_sort_list_two_tailed(i[1:-1]) + [i[-1]]
  return r
Recursion: Sum List
Given a list of numbers 'i[]'

- Return the sum of all elements in i
- Also include any numbers in nested lists as addends to the sum

solution screenshot
def recursive_sum_list(i):
  r = 0
  if not isinstance(i, list):
    return i
  for ind in range(len(i)):
    if isinstance(i[ind], list):
      nested = recursive_sum_list(i[ind])
      r += nested
    else:
      r += i[ind]
  return r
Recursion: Flatten List
Given a list 'i[]'

- Return the array as a single dimension (i.e. merge the contents of any nested arrays into the root level)

solution screenshot
def recursive_flatten_list(i):
  r = []
  if not isinstance(i, list):
    return i
  for a in i:
    if isinstance(a, list):
      b = recursive_flatten_list(a)
      for c in b:
        r.append(c)
    else:
      r.append(a)
  return r
Recursion: Palindromes in String
Given a string 'text'

- Return a list of the palindromes contained within text

solution screenshot
def recursive_palindromes_in_str(text):
  r = []
  def eval_palindrome(current, text, r):
    if len(current) > 1 and current == current[::-1]:
      if current not in r:
        r.append(current)
    for idx in range(len(text)):
      eval_palindrome(current+text[idx], text[idx+1:], r)
      current = ""
  eval_palindrome("", text, r)
  return r
Recursion: Find Value From Key
Given a dictionary object "x{}" and key "y":

- Recursively find the value for key y within x (including any keys nested within x)
- Return the key's value if found in x, otherwise return None

solution screenshot
def recursive_find_key_value(x, y):
  if not isinstance(x, dict):
    return None
  for z in x.keys():
    if isinstance(x[z], dict):
      v = recursive_find_key_value(x[z], y)
      if v:
        return v
    if (z == y):
      return x[z]
  return None
Regex: validate emails
Given a list of emails and a domain; return a list of the valid emails under the domain name.

- The username for the emails will be alphanumeric


solution screenshot
import re

def regex_email_eval(li, domain):
  valid_emails = []
  for i in li:
    a = re.match("[a-zA-Z0-9]+@"+domain.replace('.','\.')+"$", i)
    if a != None:
      valid_emails.append(a.group(0))
  return valid_emails
HTTP Requests: URL status
Validate a URL using an http_get protocol

- If the status code is returned as 2xx; return it under a successful status
- If the status code is not 2xx; return it under a different status
- If an error occurs while processing the request; catch and print the exception

solution screenshot
import requests as req

def validate_url(url):
  try:
    a = req.get(url)
    sc = a.status_code
    if str(sc)[0] == '2':
      s = 'success'
    else:
      s = 'info'
    r = {'url':url, 'status':s, 'status_code':sc}
    print(str(r) + '\n')
    return r
  except Exception as e:
    print('error - ' + str(e) + '\n')
Logger: log message to a file
Log a message to a logfile and include details on the status, date, and time.

- Provide the option to specify the status of the message (e.g. INFO, WARNING, ERROR)
- Output the logs to a datestamped file
- Include a datetimestamp of when the log was appended

solution screenshot
import logging
import datetime as dt

def logfile(filename, message, type):
  filename += '_' + dt.datetime.now().strftime('%d-%m-%Y')
  logging.basicConfig(filename=filename+'.log', level=logging.DEBUG)
  message = dt.datetime.now().strftime('%d-%m-%Y_%I:%M:%S:%f') + ' ' + message
  options = {
    'info': logging.info,
    'warning': logging.warning,
    'error': logging.error,
    'critical': logging.critical
  }
  options[type](message)
  return
JSON: get attributes from file
Given a JSON file and list of attributes, return a list of each attribute's values from the file

- Include inputs for the filename and a list of attributes to retrieve
- If no attributes are specified, return the JSON file as a dictionary
- If the attribute does not exist, raise a DNE exception

solution screenshot
import json

def get_json_attrs(fp, attrs=[]):
  try:
    f = open(fp, "r")
    j = json.load(f)
    return [recursive_find_key_value(j, value) for value in attrs]
  except Exception as e:
    print('error for ("' + fp + '", ' + str(attrs) + ') - ' + str(e))
Timeit: Measure Function Execution Time
Given a function 'func(args)', use the timeit module measure the time to execute the function.

- Include for a parameter to allow the function to be run repeatedly
- If there are multiple runs, indicate the fastest run

solution screenshot
import timeit

def time_func(func, setup_func, number=1000, repeat=1):
  setup = "from __main__ import " + setup_func
  if repeat > 1:
    result = timeit.repeat(func, setup, number=number, repeat=repeat)
    result.append({'fastest run': min(result)})
  else:
    result = timeit.timeit(func, setup, number=number)
  return result
OS: rename directory files with date
Given a path of a directory containing files

- Prefix the directory's filenames with a datestamp

solution screenshot
import os
import datetime as dt

def rename_directory_files_with_date(path):
  try:
    files = os.listdir(path)
    d = dt.datetime.now().strftime('%d%m%Y')+'_'
    for file in files:
      os.rename(path+file, path+d+file)
    return
  except Exception as e:
    print(e)
OS: Get Environment Variable Values
Given a list of an OS's environment variables

- Get the values for the environment variables
- Return a dictionary in the form {"env_var_name": "env_var_value", ... }

solution screenshot
import os

def get_env_vars(vars):
  r = {}
  for var in vars:
    r[var] = os.getenv(var)
  return r
Threading: Multithreading Functions
Use multithreading to run a list of functions across multiple threads

- Allow for a list of both functions and arguments to be passed as inputs
- For each function element in the input list, start a Thread object

solution screenshot
import threading

def multithreading_functions(inputs):
  for input in inputs:
    t = threading.Thread(target=input["function"], args=(*input["args"],))
    t.start()
    print(str(t) + " \nstarting function " + input["function"].__name__ + \
    " with args " + str(input["args"]) + "\n")
Regex: Is String Input Sanitized
Given a string input, check to see if it is sanitized to be passed to a shell command

- The string should only contain alphanumeric characters, periods, dashes, and underscores.
- If the string contains only these characters, return True; otherwise, return False

solution screenshot
import re

def is_valid_input(text):
  a = re.search('[^\-\.\w]', text)
  if a == None:
    return True
  return False
Random: Randomize Sets
Given a list of elements and int x,

- Randomly distribute the list elements into x sets
- Try to distribute the elements evenly across the sets (e.g. 10 items and 2 sets should return 5 elements in each set).
- If the elements cannot be distributed to the sets evenly (i.e. len(list)%x != 0), distribute the remaining items among the sets.
- Return a copy of the list as sets; ensure the input list is not mutated

solution screenshot
import random as r

def randomize_sets(points, num_sets):
  sets = []
  points = points.copy()
  for num in range(num_sets):
    sets.append([])
  while points:
    for set in sets:
      if not points:
        break
      random_index = r.randint(0, len(points)-1)
      set.append(points[random_index])
      del points[random_index]
  return sets
Get Duplicates and Number Occurances
Given a list s,

- Return a list of items in s that have duplicates and the number of occurances of each duplicate

solution screenshot
def get_duplicates_and_number_occurances(s):
  d = {}
  for i in s:
    if i not in d:
      d[i] = 1
    else:
      d[i] += 1
  return [[k,v] for k,v in d.items() if v > 1]
Longest Unique Substring
Given a string s,

- Return the longest substring containing only unique characters in s

solution screenshot
def longest_uniq_substr(s):
  if len(s) == 0:
    return s
  c = {}
  for idx in range(0, len(s)):
    c[idx] = s[idx]
  for i in c.keys():
    for j in range(i, len(s)-1):
      if s[j+1] in c[i]:
        break
      c[i] += s[j+1]
  max_len = max([len(k) for k in c.values()])
  for a in c.values():
    if len(a) == max_len:
      return a
  return ""
Numbers and Letters
Given a string s,

- Return a dictionary with the keys for numbers, letters, and other characters and values as the input characters based on their corresponding key classification.

solution screenshot
import re

def numbers_and_letters(s):
  ltr_check = re.compile('[a-zA-Z]')
  num_check = re.compile('[0-9]')
  result = {
    "letters": "",
    "numbers": "",
    "other": ""
  }
  for chr in s:
    if ltr_check.match(chr):
      result["letters"] += chr
    elif num_check.match(chr):
      result["numbers"] += chr
    else:
      result["other"] += chr
  return result
Within Base 2
Given a positive integer num,

- Return the exponential of base 2 which can contain the num value (i.e. the lowest base 2 value greater than or equal to the num value)

solution screenshot
def within_base_2(num):
  i = 0
  while True:
    if num > 2**i:
      i+=1
    else:
      break
  return i
Replace File Text
Given a filename file, text textToReplace, and text newText,

- Replace the instances of textToReplace to newText in the file
- Overwrite the original file contents with the updated file



solution screenshot
def replace_file_text(file, textToReplace, newText):
  rfile = open(file)
  lines = rfile.readlines()
  newLines = list(map(lambda line: line.replace(textToReplace, newText), lines))
  rfile.close()

  wfile = open(file, mode='w')
  wfile.write("".join(newLines))
  wfile.close()
  return
Pair Sum
Given a list of elements s and int n,

- Find the pair(s) of numbers in s that sum to n


solution screenshot
def pair_sum(n, s):
  pairs = []
  for i in range(len(s)):
    for j in s[i+1::]:
      if s[i] + j == n:
        pairs.append([s[i], j])
  return pairs
Max Diff in List RL
Given a list of numbers s,

- Return the maximum difference between the possible pairs of numbers from right to left

solution screenshot
def max_diff_in_list_rl(s):
  max_diff = 0
  idxs = [0,0]
  for i in range(len(s)):
    for j in range(i+1, len(s)):
      if s[j]-s[i] > max_diff:
        max_diff = s[j]-s[i]
        idxs = [i,j]
  return idxs
Max Diff in List LR
Given a list of numbers s,

- Return the maximum difference between the possible pairs of numbers from left to right

solution screenshot
def max_diff_in_list_lr(s):
  max_diff = 0
  idxs = [0,0]
  for i in range(len(s)):
    for j in range(i+1, len(s)):
      if s[i]-s[j] > max_diff:
        max_diff = s[i]-s[j]
        idxs = [i,j]
  return idxs
Get Matching Substrings
Given 2 strings 'txt1' and 'txt2',

- Return a list of all the substrings common between txt1 and txt2

solution screenshot
def matching_substr(txt1, txt2):
  r = []
  for i in range(len(txt1)):
    for j in range(len(txt2)):
      if txt1[i] == txt2[j]:
        r.append(txt1[i])
        isMatch = True
        count = 1
        while isMatch:
          isMatch = False
          if i+count == len(txt1) or j+count == len(txt2):
            break
          if txt1[i+count] == txt2[j+count]:
            isMatch = True
            count += 1
            r.append(txt1[i:i+count])
  return r
Get Local Items of Item
Given value 'item', list of values 'items', and number 'span',

- Return a list containing the elements in 'items' within the 'span' of 'item'
- If 'item' occurs multiple times in 'items', include all span items for each instance as a list.
- Example: get all items in [1,2,3,4,5,6,7,8] within 2 places of the value 5 (this should return [3,4,5,6,7])


solution screenshot
def get_item_locals(item, items, span):
  r = []
  for i in range(len(items)):
    if items[i] == item:
      start = i-span
      end = i+span+1
      if start < 0:
        start = 0
      if end > len(items):
        end = len(items)
      r.append(items[start:end])
  return r
Horizontal to Vertical Text
Given a list of strings 'lines',

- Return a list containing the characters of lines such that the line's characters are formatted from top to bottom

solution screenshot
def htov_text(lines):
  max_char = max([len(line) for line in lines])
  r = [[' ' for m in range(len(lines))] for n in range(max_char)]
  for i in range(len(lines)):
    for j in range(len(lines[i])):
      r[j][i] = lines[i][j]
  return r
Get Iterative Palindromes in String
Given a string 'text',

- Return a list of the palindromes contained within text


solution screenshot
def iterative_palindromes_in_str(text):
  def is_palindrome(s):
    return s == s[::-1]
  r = []
  c = []
  for letter in text:
    for idx in range(len(c)):
      c[idx] += letter
      if is_palindrome(c[idx]) and c[idx] not in r:
        r.append(c[idx])
    c.append(letter)
  return r
Validate Enclosing Brackets
Given a string 's', validate if all brackets are enclosed in their respective scope

- Return true if all brackets are enclosed within their scope - Return false if any bracket is not enclosed

solution screenshot
def validateEnclosingBrackets(s):
  r = []
  brackets = [
    ["(", ")"],
    ["{", "}"],
    ["[", "]"]
  ]
  for c in s:
    for b in brackets:
      if c == b[0]:
        r.append(b[1])
        break
      if c == b[1]:
        if len(r) > 0 and c == r[-1]:
          r = r[:-1]
          break
        else:
          return False
  if len(r) != 0:
    return False
  return True
Get Factors
Given an integer 'x', return a list of the factors of 'x'

- Ensure the list of factors are unique (e.g. 9's factors are 1,3,9 instead of 1,3,3,9)
- If no factors are found, return an empty list

solution screenshot
def get_factors(x):
  i=1
  r=[]
  while (i <= x//i):
    if (x%i == 0):
      r.append(i)
      (i != x//i) and r.append(x//i)
    i+=1
  return r
Get Matrix Column by Index
Given a 2d matrix 'matrix[][]' and integer 'index', return a column list for the given matrix's index

- If the index for the matrix is out of bounds, return None

solution screenshot
def get_column_by_index(matrix, index):
  col = []
  if index not in range(len(matrix[0])):
    return None
  for row in matrix:
    col.append(row[index])
  return col
Get Matrix Column by String
Given a 2d matrix 'matrix[][]' and string 'text', return a column list where the matrix's column title matches 'text'

- If there is no column title which matches 'text', return None

solution screenshot
def get_column_by_string(matrix, text):
  col = []
  if text not in matrix[0]:
    return None
  index = matrix[0].index(text)
  for row in matrix:
    col.append(row[index])
  return col
Percent Diff
Given two integers 'i' and 'j', return the percentage value of the delta relative to i

- Example; a percentage diff from 10 to 15 should be 50% as the delta (5) is 50% of 10.
- Account for changes in decreasing values as well (e.g. the percent diff from 5 to 2 is -60%)

solution screenshot
def percent_diff(i,j):
  return (j-i)/i*100
Sets of x
Given a list 'data[]' and integer 'x', return a list of sets with 'x' items from 'data[]'

- Append any remainder items to the list if it cannot form a full set of 'x' items

solution screenshot
def sets_of_x(data, x):
  r = []
  i = 0
  for a in range(len(data)//x):
    r.append(data[i:i+x])
    i+=x
  (len(data[i:len(data)]) > 0) and r.append(data[i:len(data)])
  return r
Simplified Fraction
Given a string 'f' representing a fraction, return a string representing the simplified form of 'f'

- Example: a string input of "18/24" should return "3/4"

solution screenshot
def simplified_fraction(f):
  n = int(f.split("/")[0])
  d = int(f.split("/")[1])
  d_factors = get_factors(d)
  d_factors_sorted = sort_list(d_factors)
  lcd = 1
  for factor in d_factors_sorted:
    if n % factor == 0:
      lcd = factor
  return str(int(n/lcd)) + "/" + str(int(d/lcd))
Weighted Percents
Given a list of numbers 'ns', return a list of the weighted percentage of the composition of 'ns'

- Example: a list of [1, 1, 2] should return [25.0, 25.0, 50.0] as the items are weighted from a sum of 100%
- Return the result as a list of floats and specify precision of up to three decimal points

solution screenshot
def weighted_percents(ns):
  s = 0
  r = []
  for n in ns:
    s+=n
  i = 100/s
  for n in ns:
    r.append(round(n*i, 3))
  return r
Within Percent Variance
Given a list of numeric items 'data[]', a numeric value 'percent', and numeric value 'num',
return the items in 'data[]' that are within the 'percent' variance of 'num'

- Example: the variance within 20% of 100 should return any 'data[]' items within the range of '80' and '120'
- Variance bounds should include of the upper and lower limit values

solution screenshot
def within_percent_variance(data, percent, num):
  r = []
  ll = num*(1-percent*0.01)
  ul = num*(1+percent*0.01)
  for a in data:
    if a >= ll and a <= ul:
      r.append(a)
  return r
Randomize List
Given list 'li[]':

- Return a randomly ordered list of 'li'

solution screenshot
import random as r

def randomize(li):
  a = []
  list = li.copy()
  for e in range(0, len(list)):
    i = r.randint(0, len(list)-1)
    a.append(list[i])
    del list[i]
  return a
Parse URL Query
Given a string 'q':

- Parse out the url query's key-value pairs and return the pairs in a dictionary

solution screenshot
def url_query(q):
  a = q[q.find('?')+1::]
  r = {}
  while(a.find('&') != -1):
    r[ a[0:a.find('=')] ] = a[a.find('=')+1:a.find('&')]
    a = a[a.find('&')+1::]
  r[ a[0:a.find('=')] ] = a[a.find('=')+1::]
  return r
Get Elements Greater/Less Than
Given a list of numbers "lst[]", int "num", and greater/less than character "s"

- Return all elements in lst[] that are greater or less than num based on the comparison character "s"

solution screenshot
def get_elems_greater_less_than(lst, num, s):
  return {
    '>': [i for i in lst if i > num],
    '<': [i for i in lst if i < num]
  }[s]
Are Elements the Same Type
Given list "lst[]"

- Determine if all the elements in lst are of the same type
- If all elements are of the same type return True
- If there is more than one type of element in lst return False
- If there are less than two elements in lst return None (comparisons need at least two items)

solution screenshot
def is_elems_same_type(lst):
  if len(lst) > 1:
    t = type(lst[0])
    for e in lst[1:]:
      if t != type(e):
        return False
    return True
  return None
Run a Function Multiple Times
Given a function 'func(args)' and int 'x'

- Run the function and any arguments x times
- If args or number of runs aren't specified, assume empty *args and one run

solution screenshot
def run_x_times(func, args=[], x=1):
  for a in range(x):
    func(*args)
Get Substring Count in String
Given a string 's' and substr 'x':

- Return the number of occurances of 'x' in 's'

solution screenshot
# soln 1
def x_count_in_string(s, x):
  r = 0
  while (True):
    if s.find(x) != -1:
      r += 1
      s = s[s.find(x)+1:]
    else:
      break
  return r

# soln 2
def x_count_in_string_2(s, x):
  r = 0
  for a in range(len(s)-len(x)+1):
    if s[a:a+len(x)] == x:
      r += 1
  return r
Get Indices of Substring in String
Given string 's' and substr 'x'

- Return a list of the indexed occurances of 'x' in 's'

solution screenshot
# soln 1
def get_indices_of_x_in_string(s, x):
  r = []
  a = 0
  while (True):
    b = s.find(x)
    if b != -1:
      a += b
      r.append(a)
      s, a = s[s.find(x)+1:], a+1
    else:
      break
  return r

# soln 2
def get_indices_of_x_in_string_2(s, x):
  r = []
  for a in range(len(s)-len(x)+1):
    if s[a:a+len(x)] == x:
      r.append(a)
  return r
Get Elements Containing Substring
Given a list strings 'a[]' and substr 's'

- Return a list of items in 'a[]' that contain substr 's'

solution screenshot
def get_elems_with_substr(a, s):
  return [r for r in a if r.find(s) != -1]
Linear Regression
Given a list of points (e.g. [(x1,y1),(x2,y2)...(n1,n2)]

- Calculate the linear regression with the form (y = a + b*x)
- Return a dictionary containing the values of a and b, and the formula of (a + b*x)

solution screenshot
def lin_reg(ls):
  n, xy, x2, y2, x, y = len(ls), 0, 0, 0, 0, 0
  for i in range(0,len(ls)):
    x += ls[i][0]
    y += ls[i][1]
    x2 += ls[i][0]**2
    y2 += ls[i][1]**2
    xy += ls[i][0]*ls[i][1]
  a = ((y*x2)-(x*xy))/((n*x2)-x**2)
  b = ((n*xy)-(x*y))/((n*x2)-x**2)
  return {'a':a, 'b':b, 'formula':'y = '+str(a)+' + '+str(b)+'*x'}
Max And Min
Given a list 'list[]':

- Return a dictionary containing the maximum value and minimum values in 'list'

solution screenshot
def min_max(list):
  r = [list[0]]
  for e in range(1,len(list)):
    if list[e] > r[-1]:
      r.append(list[e])
    elif list[e] < r[0]:
      r.insert(0, list[e])
  return {"max": r[-1], "min": r[0]}
Is Prime
Given int 'n'

- Return True if 'n' is prime
- Return False if 'n' isn't prime along with the factor where the prime test fails

solution screenshot
def is_prime(n):
  i = 2
  while(i <= n//i):
    if n%i == 0:
      return {False, "divisible by %i" % i}
    i+=1
  return True
Is IPv4
Determine if string 'ip' is a valid IPv4 address

- Return True if 'ip' is valid and False if 'ip' is invalid

solution screenshot
def is_ipv4(ip):
  a = ip.split('.') if len(ip.split('.')) == 4 else []
  if not a:
    return False
  for i in a:
    if i.isalpha() or not (0 <= int(i) <= 255):
      return False
  return True
Datestamp File
Create a datestamped file

- Allow optional text to be passed to the file

solution screenshot
import datetime as dt

def datestamp_file(fn='', content=''):
  d = dt.datetime.now()
  f = open(fn+d.strftime('%d-%m-%Y.txt'),'w+')
  f.write(content)
  f.close()

Equalize Matrix Dimensions
Given a matrix containing lists of various lengths

- Return a matrix with the lists as the same length (i.e. set the lists to the same size as the largest list in the matrix)
- Allow a placeholder to be used for expanding lists

solution screenshot
def matrix_form(matrix, placeholder):
  max_row = 0
  m = []
  for row in matrix:
    if len(row) > max_row:
      max_row = len(row)
  for row in matrix:
    diff = max_row - len(row)
    if diff > 0:
      m.append(row+[placeholder]*diff)
    else:
      m.append(row)
  return m
Get Average
Given a list of numbers 'lst[]'

- Return the average value of the lst items

solution screenshot
def get_average(lst):
  a = 0
  for i in lst:
    a += i
  return a/len(lst)
Get Focal Point
Given a list of points 'pts[]'

- Return the focal point (average) of the items
- Allow for multi-dimensional points (e.g. 2D [2,4], 3D [3,6,9])

solution screenshot
def get_focal_point(pts):
  ptlen = len(pts[0])
  r = [0]*ptlen
  for a in range(0,ptlen):
    for pt in pts:
      r[a] += pt[a]
    r[a] /= len(pts)
  return r
Get n Vals
Given a list of numeric values 'lst[]', number of items 'n', and top/bottom option 't'

- Return the top/bottom 'n' items of lst (e.g. return the top 5 items in sample list)
- Allow option 't' to specify whether to retrieve the top/bottom items (default should retrieve the top items)
- If top results are specified, return them from highest to lowest values
- If bottom results are specified, return them from lowest to highest values

solution screenshot
def get_n_vals(lst, n, t=1):
  s = sort_list(lst)
  if (t):
    return s[len(s)-1:len(s)-1-n:-1]
  return s[:n]
Get n Vals Percentile
Given a list of numeric values 'lst[]', percentile value 'p', and top/bottom option 't'

- Return the top/bottom 'p' items of lst (e.g. return the top 25% of items in sample list)
- Allow option 't' to specify whether to retrieve the top/bottom items (default should retrieve the top items)
- If top results are specified, return them from highest to lowest values
- If bottom results are specified, return them from lowest to highest values
- Allow option 'r' to specify whether to round the number of percentile items up/down (default should retrieve number of items rounded up)

solution screenshot
import math

def get_n_vals_percentile(lst, p, t=1, r=1):
  s = sort_list(lst)
  i = {
    0: math.floor(len(lst)*(p/100)),
    1: math.ceil(len(lst)*(p/100)),
    }[r]
  if (t):
    return s[len(s)-1:len(s)-1-i:-1]
  return s[:i]
Fibonacci Number
Given a sequence number (n), return the fibonacci number of the sequence step

solution screenshot
def fibonacci_number(n):
  if n <= 1:
    return n
  previous2 = 0
  previous1 = 1
  current = None
  for a in range(1,n):
    current = previous1 + previous2
    previous2 = previous1
    previous1 = current
  return current
Fibonacci Series
Given a sequence number (n), return the fibonacci series of the sequence step

solution screenshot
def fibonacci_series(n):
  if n <= 1:
    return list(range(n+1))
  previous2 = 0
  previous1 = 1
  current = None
  r = [0,1]
  for a in range(1,n):
    current = previous1 + previous2
    r.append(current)
    previous2 = previous1
    previous1 = current
  return r
Spiral Matrix (clockwise)
Given a 2d matrix (matrix), return a list of the matrix items that form a cw spiral pattern

- Start from the upper left item of the matrix
- Ensure the spiral pattern is in a clockwise direction

solution screenshot
def spiral_matrix(matrix):
  a = []
  top = 0
  right = len(matrix[0])-1
  bottom = len(matrix)-1
  left = 0
  iteration = 0
  num_matrix_items = len(matrix[0])*len(matrix)

  for x in range(0,(len(matrix)//2)+1):
    # top
    if (len(a) >= num_matrix_items-1):
      if len(a) != num_matrix_items:
        a.append(matrix[top][iteration])
      break
    for item in matrix[top][iteration:-1-iteration]:
      a.append(item)
    # right
    if (len(a) >= num_matrix_items-1):
      if len(a) != num_matrix_items:
        a.append(matrix[iteration][right])
      break
    for row in matrix[iteration:-1-iteration]:
      a.append(row[right])
    # bottom
    if (len(a) >= num_matrix_items-1):
      if len(a) != num_matrix_items:
        a.append(matrix[bottom][len(matrix[bottom])-1-iteration])
      break
    for item in reversed(matrix[bottom][1+iteration:len(matrix[bottom])-iteration]):
      a.append(item)
    # left
    if (len(a) >= num_matrix_items-1):
      if len(a) != num_matrix_items:
        a.append(matrix[len(matrix)-1-iteration][left])
      break
    for row in reversed(matrix[1+iteration:len(matrix)-iteration]):
      a.append(row[left])
    # iterate
    top += 1
    right -= 1
    bottom -= 1
    left += 1
    iteration += 1
  return a
Spiral Matrix (counterclockwise)
Given a 2d matrix (matrix), return a list of the matrix items that form a ccw spiral pattern

- Start from the upper right item of the matrix
- Ensure the spiral pattern is in a counterclockwise direction

solution screenshot
def spiral_matrix_ccw(matrix):
  a = []
  top = 0
  right = len(matrix[0])-1
  bottom = len(matrix)-1
  left = 0
  iteration = 0
  num_matrix_items = len(matrix[0])*len(matrix)

  for x in range(0,(len(matrix)//2)+1):
    # top
    if (len(a) >= num_matrix_items-1):
      if len(a) != num_matrix_items:
        a.append(matrix[top][len(matrix[top])-1-iteration])
      break
    for item in reversed(matrix[top][1+iteration:len(matrix[top])-iteration]):
      a.append(item)
    # left
    if (len(a) >= num_matrix_items-1):
      if len(a) != num_matrix_items:
        a.append(matrix[iteration][left])
      break
    for row in matrix[iteration:-1-iteration]:
      a.append(row[left])
    # bottom
    if (len(a) >= num_matrix_items-1):
      if len(a) != num_matrix_items:
        a.append(matrix[bottom][iteration])
      break
    for item in matrix[bottom][iteration:-1-iteration]:
      a.append(item)
    # right
    if (len(a) >= num_matrix_items-1):
      if len(a) != num_matrix_items:
        a.append(matrix[len(matrix)-1-iteration][right])
      break
    for row in reversed(matrix[1+iteration:len(matrix)-iteration]):
      a.append(row[right])
    # iterate
    top += 1
    right -= 1
    bottom -= 1
    left += 1
    iteration += 1
  return a
Pop Random
Given a list of items (li), pop a random item from the list

- The list should be updated in-place with the random item removed
- Return the removed item from the function

solution screenshot
def pop_random(li):
  i = random.randint(0, len(li)-1)
  d = li[i]
  del(li[i])
  return d
Sum Matrices
Given two 2d matrices (m1) and (m2), return a 2d matrix of their total sum

- the matrices (m1) and (m2) are of the same dimensions


solution screenshot
def sum_matrices(m1, m2):
  r = m1.copy()
  for i in range(len(m1)):
    for j in range(len(m1[0])):
      r[i][j] += m2[i][j]
  return r