Let’s Talk Template Literals

It’s interesting that there are so many ways to STDOUT text to the screen. Let’s look at a few of them in JavaScript (ES6) and Python (3.6)

Concatenation: This works in both JavaScript (console.log) and Python (print). “The first half of the sentence ” + “is joined to the second with a plus sign between the halves.” Also works with variables. “Hello, ” + user.name + ” and welcome to our shopping site.” Do pay attention to where spaces are.

Embedded expressions: Javascript allows developer to include simple expressions as well.

console.log( "Hello, " + user.name + ". Your total is: " + (purchase.subTotal + purchase.tax + purchase.delivery) + ".")

Hello, Kristopher. Your total is $123.45.

String formatting: Python 3.6 allows developers to include variables mid-string as follows:

print('We are the {} who say "{}!"'.format('knights', 'Ni')) 

We are the knights who say "Ni!"

But if you need to refer to the position of the argument (values passed in to ‘format()’ there’s also:

print('{0} and {1}'.format('spam', 'eggs')) 
spam and eggs

or:

print('{1} and {0}'.format('spam', 'eggs')) 
eggs and spam

As well as keyword arguments, though I find this exceptionally cumbersome and wonder why the developer wouldn’t jut hard-code the values into this sentence. I’m including it because it’s in the Python docs and isn’t noted as being too archaic:

print('This {food} is {adjective}.'.format(food='spam', adjective='absolutely horrible')) 

This spam is absolutely horrible.

My personal preference, added to Python in 3.6 is the f-string

print(f'Welcome, {user.name}! Today's special is {special.name} and is on sale for {special.price}.')

Welcome, Kristopher! Today's special is Singing Rooster Coffee 12oz vacuum bag and is on sale for $10.

This is really easy to debug, in part because it reads very much like the end sentence, without extra punctuation. I also don’t have to type-cast my variables like in Python 2.7 (which required %s, %f and %i when referring to strings, floats and integers). Take a look at the Python docs for more examples and explanations: https://docs.python.org/3/tutorial/inputoutput.html

In JavaScript I’m growing attached to template literals. Like the f-string a template literal reads very much like the final product.

console.log(`Welcome, ${user.name}! Today's special is ${special.name} and is on sale for ${special.price}.`

Welcome, Kristopher! Today's special is tomato soup with grilled cheese sandwich and is on sale for $6.75.

The only catch here is to look for backticks (“ the keys that are left of the “1” on a US keyboard). At first they can look like single quotes, though most IDEs I’ve worked with do a good job of making the angle very obvious. MDN has done a great job with the documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

Let’s Talk Template Literals

But Your Github….

Screen Shot 2018-09-14 at 12.10.57 PM

This is my github contribution chart as of today (github). Of the few recruiters who have looked at my account one of them said “it doesn’t look like you contribute much code”. As I’m heavily back into the job search process I thought I would take a moment to explain “gaps”.

  1. I don’t typically contribute tutorial code. I have occasionally done so. The Harvard CS50 class requires that I have github integration so I can submit assignments. Andrew Ward’s Complete React Training at Udemy requires updates to a github repo as he has us deploy to heroku. But for the most part I figure this is code that is a) not mine and b) readily available from the original tutorial.
  2. I did commit my solutions to the homework that was assigned while I was a teaching assistant at University of Washington for a Python class. These are my original solutions to the assignments which I used as a guide for helping students. I don’t consider them tutorial or code-along-project code.
  3. The large gray chunk in June and July represents tutorial-heavy study time as well as a couple weeks I took off to prepare for my significant other’s birthday (we rented a hall, it was catered and we had out-of-town guests; things needed managing).
  4. With my previous employer my team lead was in charge of squashing commits and merging with master branch. While my unmodified code was credited to my account he most often made subtle changes (and some not so subtle) before merging. As far as git is concerned those are his commits and it was a sticking point between him, our CTO and me.
  5. Most of my code experiments end up on Repl.it or Codepen. I don’t feel the need to also commit that code to version control.

So that’s it in a nutshell.  I do code daily as I’m working to master React and the ecosystem that surround that library, as well as improving my learning in Python. While I am learning a lot and improving every day, it’s not code I’m “proud” of nor does it demonstrate my capabilities, which is what I think git should be used for outside of its professional uses.

But Your Github….

Foundations of Programming: Python Class is in the Books

Last night we had project presentations for the Foundations of Python class I TA’d at University of Washington. To a person I was extremely impressed with their projects and the progress they made.

Overall the class was made up of people who had little to no coding experience. Some of these folks had never used their terminal before. Others had experience with R, SQL and GIS programs, but used them to solve specific problems rather than code out programs that were reusable.

I don’t remember all of the projects but these are those that stuck with me:

  • A neuroscientist who used Jupyter Notebooks to track comparative mortality due to Alzheimer’s Disease using CDC data
  • An applied math PhD candidate who plotted the collaborative-ness of various email and document networks in her department
  • One student used BeautifulSoup to scrape articles for information about cheese prices, then made a local data store that the user can update with their own findings. He did not call the data store ‘cheese_cellar’ – missed opportunity there.
  • A security specialist for a financial institution made a suite for determining if credit card numbers had been compromised. He wrote a script to generate fake, semi-randomized 24-character “credit card numbers” and “compromised credit card numbers” like those on the dark web. His final script then compared the two lists and outputted a “compromised” list and a second list of the remaining numbers. The cardholders on the first list would be contacted and security would try to find a common merchant that could be the source of the breach. He said security could use this second list to contact the issuers of those cards and the organizations could collectively trace the origin of the data breach. Very impressive for someone whose previous experience was in BASIC.
  • A project manager automated a task wherein she has to normalize file names every month for her org’s data processing group. Typically this task took three or more hours and now takes seconds. She even accounted for unique files names that didn’t fit the pattern of 95% of the files she has to rename. I referenced Automate the Boring Stuff with Python and she replied “that was my inspo for this project… that and not having to do this by hand anymore”.

My takeaways from the class are several. First I’m impressed with how accessible Python is, not just to write but in the suite of tools that are available. For most students the biggest hurdle was learning how to read HTML so they could figure out which elements to target with BeautifulSoup. I admire the creativity of the folks who weren’t solving a work problem, and I’m awed by the amount of work that the work-problem-solvers were able to automate.

If you’re interested in Python programming, I highly recommend the text for this course, Python Programming for Absolute Beginners. The style is approachable and I didn’t find the pace overwhelming. If you make a Python project, let me know in the comments!

Foundations of Programming: Python Class is in the Books

Thoughts on Data Structures Related to Linked Lists, in the Key of Python

Apologies in advance for the wonky formatting.
This started as a gist at https://gist.github.com/KMSkelton/1b1c0ecf59d8b7406e3495f831184ad1
and I decided to also make it a blog post for easier reference. It
turns out gists are not easy to get to via Github on my phone.

I am using Python3 because it is better suited for data structures
than is JavaScript. I understand there may be some code formatting
issues that betray my background in JavaScript, and I am happy to
discuss best practices. The mea culpa and ado concluded…

A linked list is a collection of data comprised of nodes. 
Each node is either empty or it contains "cargo" and a reference
 to the next node in the list (for a singly linked list) or 
references to the next node and the previous node (for a doubly 
linked list). The advantage to linked lists is that we do not have
 to allocate memory to them; the nodes will add themselves to 
memory wherever they have room. Insertions are super fast [O(1)] 
as are removals because we typically work from the ends. 
The trade off is that the entire list has to be traversed to find 
the data being requested, so all find operations are O(n). 
There are no external references to locations in a linked list 
(unlike an array which is indexed and is contiguous in memory).
This is the most basic form of a node in a linked list:
class Node:
  def __init__(self, cargo=None, next=None):
     self.cargo = cargo
     self.next = next
     
  def __str__(self):
    return str(self.cargo)

node1 = Node(1)
node2 = Node(2)
node3 = Node(3)

This inserts three integers into three locations that are 
patterned after the Node class above. It will be more useful if we
are able to retrieve more than one item that we already know the 
location of (i.e. let's add links).

node1.next = node2
node2.next = node3

This is OK for brute force creation of the most basic of linked 
lists. As it is we can search for a Node if we know it's there, 
but we can't return a list or remove a Node.
A little functional panache will make things easier for searching 
and updating the list. From the top we'll establish all the 
properties of the Node: 

class Node:
  def __init__(self, cargo=None, next=None):
     self.cargo = cargo
     self.next = next
     
  def getCargo(self):
    return self.cargo
  
  def setCargo(self, val):
    self.cargo = val
    
  def nextNode(self):
    return self.next
    
  def setNextNode(self,val):
    self.next = val

#Next we need to be able to make and modify the linked list itself
#this prints as a STACK or first-in last-out (FILO) or 
# Last In First Out (LIFO) implementation

  def __init__(self,head=None):
    self.head = head
    self.size = 0
  
  def getSize(self):
    return self.size
    
  def addNode(self, cargo): # Typically stacks call this a push
    newNode = Node(cargo, self.head)
    self.head = newNode
    self.size += 1
    return True
    
  def printNodes(self):
    current = self.head
    while current:
      print(current.cargo)
      current = current.nextNode()

# Alias LinkedList as myList to make things slightly easier      
myList = LinkedList()
myList.addNode(4)
myList.addNode(50)
myList.addNode(37)
myList.printNodes() # 37 50 4

# Let's simply discover whether a value exists in the linked list 
# (True or False). This is done by traversing through each
# node and comparing node.cargo to the value in question. 

def findNode(self,value):
  current = self.head
  #as long as there is a 'self' this process will continue
  while current: 
    #compare the cargo to the value 
    if current.getCargo() == value:
      return True
    current = current.nextNode()
  return False

# Finally let's remove a node from the list. We'll need to keep 
# track of where we are (current) and where we've been (previous) 
# This removal step begins with a search, so the worst case 
# scenario is this will take O(n) time.

def removeNode(self, value): #Typically this operation is called pop
    previous = None
    current = self.head
    
    while current:
      if current.getCargo() == value:
        if previous:
          previous.setNextNode(current.nextNode())
        else:
          self.head = current.nextNode()
        return True
        
      previous = current
      current = current.nextNode()
      
    return False
    
# Time to make this a more traditional linked list where each new 
# node is added as a tail
# This prints as a First In First Out (FIFO) structure, also 
# called a QUEUE
# Making the Node class stays the same

class Node:
  def __init__(self, cargo):
     self.cargo = cargo
     self.next = None 
# Note this is slightly different from above. No reason other than
# to demonstrate that both ways work
     
  def getCargo(self):
    return self.cargo
  
  def setCargo(self, val):
    self.cargo = val
    
  def nextNode(self):
    return self.next
    
  def setNextNode(self,val):
    self.next = val
    
# and now we need a tail
class LinkedList: 
  def __init__(self):
    self.head = None
    self.tail = None
    self.size = 0
  
  def getSize(self):
    return self.size
    
# Specifically it is the adding of nodes that is different than before. 
# Adding a node to the tail is called "enqueueing" while removing
# the head node is "dequeueing"
# I am maintaining the continuity in my verbiage to make these
# examples as easy to relate to each other as possible

  def addNode(self, cargo):
    
    # make sure the cargo is in the correct format as a Node
    cargo = Node(cargo)
            
    if ( self.head == None ):
      self.head = cargo
    else:
      self.tail.next = cargo
      
    self.tail = cargo
    return True

  def printNodes(self):
    current = self.head
    while current:
      print(current.cargo)
      current = current.nextNode()

# Finding and removing work the same as before: 

def findNode(self,value):
  current = self.head
  while current: 
    #compare the cargo to the value 
    if current.getCargo() == value:
      return True
    current = current.nextNode()
  return False

def removeNode(self, value):
    previous = None
    current = self.head
    
    while current:
      if current.getCargo() == value:
        if previous:
          previous.setNextNode(current.nextNode())
        else:
          self.head = current.nextNode()
        return True
        
      previous = current
      current = current.nextNode()
      
    return False
    
#The Doubly Linked List (DLL) adds a reference to the previous Node
class Node:
  def __init__(self, cargo):
     self.cargo = cargo
     self.next = None
     self.prev = None
     
  def getCargo(self):
    return self.cargo
  
  def setCargo(self, val):
    self.cargo = val
    
  def nextNode(self):
    return self.next
    
  def setNextNode(self,val):
    self.next = val
    
  def prevNode(self):
    return self.prev
    
  def setPrevNode(self,val):
    self.prev = val

# Now we have to consider some edge cases as well as keep track of where we are

class DoublyLinkedList: 
  def __init__(self):
    self.head = None
    self.tail = None
    self.size = 0
  
  def getSize(self):
    return self.size
    
  def addNode(self, cargo):
    newNode = Node(cargo)
    if (self.head == None):
      self.head = self.tail = newNode
    else:
      newNode.prev = self.tail
      newNode.next = None
      self.tail.next = newNode
      self.tail = newNode
    self.size += 1
    
  def removeNode(self, value):
    currentNode = self.head 
    
    while currentNode is not None:
      if currentNode.cargo == value:
        if currentNode.prev is not None:
          currentNode.prev.next = currentNode.next
          currentNode.next.prev = currentNode.prev
        else:
          self.head = currentNode.next
          currentNode.next.prev = currentNode.prev
          
      currentNode = currentNode.next
      self.size -= 1
      
  def printNodes(self):
    currentNode = self.head
    
    while currentNode is not None:
      print(" prev: {}\n cargo: {}\n next: {} ".format(
      currentNode.prev.cargo if hasattr( currentNode.prev, "cargo") else None,
      currentNode.cargo,
      currentNode.next.cargo if hasattr( currentNode.next, "cargo") else None))
      
      currentNode = currentNode.next
    return True

And there we have it. Linked Lists can be implemented in a brutish manner, or as a stack or queue. Further, adding references to where the previous node is allows us to traverse the list (potentially) faster than if we only know where the next node is.

Thoughts on Data Structures Related to Linked Lists, in the Key of Python