Friday 6 December 2013

del SLOG

From http://lans-soapbox.com/wp-content/uploads/2012/06/
so-long-and-thanks-for-all-the-fish-poster.jpg
.
On the off-chance someone is staring at this puzzled, see
http://en.wikipedia.org/wiki/So_Long,_and_Thanks_for_All_the_Fish.
Also, that same someone should probably read the
Hitchhiker's Guide to the Galaxy Series. It's weird, but good.
Also, I'm sorry for my long image captions. Though then again, maybe
apologizing in the image caption itself isn't helping things.
     Well, this is my final entry for my SLOG. I have so many fond memories, considering I finally got around to publishing everything today. I'm rather surprised, looking at some of the SLOGs in the list, how many I came across with no posts yet. Considering I'm doing this under the wire, I don't think they have much of a chance.

     In retrospect, I've made some mistakes in this course: not finishing assignment 1 in time, thinking the first test was a week after it actually was (big uh-oh there), not attending as many lectures as I could have (I don't understand how I made all the 9:00 tutorials yet could consistently wake up too late for 10:00 lectures), and so on.

     I hope I made this SLOG not too dry for whomever is marking this (looking at others', they didn't strike me as very entertaining to read). Of course, since this is being posted last, anyone reading this will look at the blog and see this post first. I've looked, but I don't see how to change the order these show up in it.

Miscellaneous thoughts:

  • How on Earth do I have 2 pageviews each from http://www.vampirestat.com/ and http://adf.ly/? Also, why did 7 people in the USA, 2 people in Serbia, and 1 person in Germany view this SLOG? Is it really that riveting?
  •  Also, my future self will probably forget about this, and stumble across it one day. Hello, future self!
  • I hope I do well in this course. Thanks for reading this!
Can you see this text? How about this one? Well, what about this one? Even this? You're really impressive! Bye! Really? You thought I'd hide text here? I'm rather offended, honestly.

Big O, little o, what begins with O?

From http://www.literaryduckblog.org/
wp-content/uploads/2011/03/77692.jpeg
.
Also, random fact: if you search "Big O"
in Google Images, most of the first
images are from a Japanese TV show called
The Big O: without this warning, you'd
be like me and mystified by all the pictures
of giant robots if you searched it.
     If you didn't understand the title, you probably didn't read Dr. Seuss's ABC book when you were young. Or you did, and just don't remember (if you need a recommendation for good books to teach little kids the alphabet, I formally endorse this one). Regardless, it's the reason I'm momentarily distracted whenever someone mentions Big O notation. By the way, the correct answer is "Ostrich, oil, orange owl."

     I'll admit it: I'm terrible with figuring out an algorithm's efficiency. It's that and the fact I maybe kinda sorta sometimes forget to hand stuff in that dropped my mark significantly in CSC165. I know it's more impressive (and obviously faster) the better an algorithm is, but I've always felt that Python was designed to be slower, yet more powerful to write and easier to read. If I was aiming to do tasks fast, I would code them in C or C++, but we write them in Python because it's easier to read and write without pouring over our code looking for an elusive semicolon.

Linked(In)Lists

From http://www.bloggingpro.com/wp-content/uploads/2012/06/chain.gif.
I guess linked lists are...like a chain? To be honest, I just really wanted to
add a picture to spice your life up. You're a cool person: don't forget that.
     Funny story: When I first heard of how linked lists work (you have a value, and it points to the next value in the list), I pictured each item as a tuple with the first value in it being the item at that index, and the second value being the memory address of the next thing. For example, I thought items would be like (7, 505894336) (or (7, 0x1e2755c0), since memory addresses make more sense in hexadecimal). However, a quick Google search for Python accessing things simply by their memory address results in people making comments like "Hopefully you're only doing this as an exercise. No reason to do this with pure Python." and "So in CPython, this will be the address of the object. No such guarantee for any other Python interpreter, though." Long story short: linked lists should not be implemented this way.

     I'll be honest: I've always been iffy about linked lists. I like to be able to access all the variables in a list at one time and not go hunting for them, and if you mess something up with something in the list, you've permanently lost everything after it in the list.

Reading Nested Lists

     I know I, for one, have troubles reading nested lists. Even for things like
[3, [7, None, [2, None, None]], [5, None, None]]
I have issues. But if you hand me something like
[1, [[2], 3, [4, 5], [6, [7, []], 8], 9], [10, [11]]]
I start to lose track of which way is up. I've looked around online for a way to make them more readable, but gave up and decided to make my own.

     After goofing around in a text editor for a bit, I decided on a layout that looked fairly good and made all the nests readable:
[1, ************************************, **********]
    [***, 3, ******, ***************, 9]  [10, ****]
     [2]     [4, 5]  [6, *******, 8]           [11]
                         [7, **]
                             []
With this exploded view, you can see how many elements are at each level and what they consist of, which makes a lot more sense! Then the question was...how should this be coded?

     There were two options, assuming we should use a list of strings as the end result: either we find the maximum depth of the nested list and create that many strings before starting, or we add a new string every time we reach a new depth. We'll assume that the nested list we're given doesn't contain strings, because

  • all the binary trees we deal with don't.
  • triple-quoted strings would be a major hassle to deal with.
     Firstly, we should find out the maximum depth of the nested list. While the program can be written without this, I was surprised to see it was consistently slower. A surprisingly elegant recursive version could be written as
def depth(x) -> int:
     """Returns the maximum depth of a nested list recursively."""
     depths = []
     for each in x:
          if isinstance(each, list):
               depths.append(depth(each))
     if depths:
          return max(depths) + 1
     return 1

     Now that we know the list's maximum depth, we can apply our knowledge.
def nest_writer(x: list, spacer: str="*") -> list:
     """Writes a nested list into a list of strings."""
     str_list = ["" for y in range(depth(x))]
     x = str(x)
     current_line = -1 # the line we care about at any time
     for char in x:
          if char == "[": 
               current_line += 1
          for each in range(len(str_list)):
               if each < current_line:
                    str_list[each] += spacer
               elif each == current_line:
                    str_list[each] += char
               else:
                    str_list[each] += " "
          if char == "]":
               current_line -= 1
     return str_list
For each character, it first checks if it's a left bracket, incrementing current_line if so. Then it uses the value of current_line as an index for str_list, so every line above it has spacer added to it, every line below it has " " added to it, and the string with index current_line has the character added to it.

     As the coup de grĂ¢ce, we'll define two more functions:
def read_lines(x: list) -> None:
     """Prints each line in x."""
     for each in x:
          print(each)

def list_reader(x: list, spacer: str="*") -> None:
     """Calls all the relevant functions to print the list."""
     read_lines(nest_writer(x, spacer))

Now, let's try it out:
>>> list_reader([1, [[2], 3, [4, 5], [6, [7, []], 8], 9], [10, [11]]])
[1, ************************************, **********]
    [***, 3, ******, ***************, 9]  [10, ****] 
     [2]     [4, 5]  [6, *******, 8]           [11]  
                         [7, **]                     
                             []                      
You can try it out with different things, but ta-da! Now you can visualize nested lists a lot better!
-----------------------------------------------------------------------------------------------------------
Edit: The funny thing is, I ended up writing this before I knew what assignment 2 was, then ended up tweaking this to help me.

Also, I have no idea why the font broke for this entry in particular. I...think it's fixed?

Bonus Update: OOP(s) and Recursively Recursing Recursion

From http://news.sabay.com.kh/wp-content/uploads
/2013/04/ObjectOrientedProgramming.png
.
Yes, the asymmetry is bothering me too.
No, I don't know why it's like that.
Well, now I feel silly. After I made two entries talking about recursion, we have to do a bonus entry about object-oriented programming and, yes, you guessed correctly, recursion! Is it too late to rename this thing Recursion: The Desolation of SLOG? (I don't know why I made that joke: I haven't even seen the previous Hobbit movie yet.)

From http://caseelse.net/wp-content/uploads/2008/05/recursionagain.jpg.
I'll confess: I do like recursion jokes.
     Anyways, object-oriented programming, as the name implies, revolves around objects, and the classes used to create them. You can give objects both attributes and methods, whereas in languages like the original FORTRAN, they have no such thing. It's useful for computer science, as you can represent things and manipulate them far easier than trying to associate random variables for each thing you're trying to represent.

     Recursion is taking a complex problem and simplifying it by having subsequent iterations of the function apply to smaller sections of the original problem until they're at their base cases and therefore easier to solve. Without it, functions would be a nightmare of trying to get things done with while loops, if they were even possible to replicate at all.

Binary Trees: Not Quite Like Family Trees

From http://lcm.csa.iisc.ernet.in/dsa/img151.gif
     I can already tell now that I'm going to have issues recursing over binary trees, let alone remembering how to implement the three versions of even listing all their items.

     I don't know if I'm just so used to seeing flat lists that I'm simply not used to them yet, but they look so strange. Besides, it must be a nightmare if you have a sorted binary tree and decide to delete a node. How do you rearrange it so it stays ordered? I looked at the Wikipedia section on the topic, but it looks like the closer the node you want to delete is to the root, the better it would be to simply power off the computer and go watch a movie.

SLOG.__init__(self)

     For those who've looked at my SLOG before and found it blank, I'm sorry: I've started a lot of drafts (or just kicked an idea around in my head), but never actually finished or fully posted any yet, so all of these are going to look back-to-back.
-----------------------------------------------------------------------------------------------------------
Yes, Google, I did mean...wait a second.
     Whenever recursion gets applied to computer science, usually one of three things happen:
  1. Bad jokes abound.
  2. The answer seems simple. "So the only cases are...okay, that makes sense."
  3. The question may as well have been written in Wingdings. "So it has to either...but it can't...what?"
     When it's things like the total sum of a nested list, life is great. But when you get to cases with unusual objects, or multiple cases, it's difficult to even start: you have to figure out what variables the function will take, and how the function will return those values to another iteration of itself for more processing, and eventually you realize you just pulled your hair out in clumps and will probably need a wig. Also, that you've still failed to write anything down.

     One thing I've noticed is that I have a bad habit to try and figure out how the internal bits of the function work: from what I've seen, it's far better to consider what the possibilities are for it to continue recursing or to be an end case and be able to start returning things. Regardless, I'm still going to need a lot more work at it: this is definitely not something that comes naturally at all.