Unsophisticated Dictionary Python

Update:1-11-18  A little more theory on magical hash.
the letters (a)'s bits are : 10000001
hash takes the characters in a string and goes to a map... it goes we are going to give each character a number based on it's bits.... does some mathy algorithmy, goes to the next character...until it returns a number for the string.
8938747498089 TADA!  every string is going to have a unique number... and every string given to it can be matched to an identical string.

If you give hash an integer it returns the integer.  It only cares about strings.
So basically it's just a giant table to store a encoded string based on an algorithm.
The magic is, it stores this data for you, encodes it for you.  If I wanted to make a random generator to put things into the dictionary, I would have to make a way to store each key's matching generated number, and that would be crazy...  Hash does that for us.  
## End hash theory ##

I got an idea today, and after I try and get the lesson on the dictionary done today, I'm going to try updating this post with my warehouse dictionary.

Why?   Why the hell not.

Actually, I got the idea today after I asked my teacher a question, because I just couldn't figure out one of the study drill's sentences.   The simple answer was:  Just put random crap into the dictionary.  Finally, a simple sentence that said exactly what I needed to do, and I can understand!  It made me giggle.  And I thought, hey.... I should do an example of this whole dictionary thing with those kinds of comments in it.  I mean, that's what I'm trying to do with this blog. What does this bloody code do, in a way anyone can read?

update-1-3-17:
Over 250 today... people in the Northern European area are digging the "playing with dictionary python" post....  Anyhoo.... Here I go trying to explain this structure. Did some digging, decided to not go the profanity route.....  There's a lot more stuff on the offensive list then I thought.  So,  what should I call it..... politically incorrect?  ..... NSFW?  That's about right... but I just want it to be plain and simple.  No pomp and circumstance... maybe a little dirt, but easy to read.

The 'Unsophisticated' version of a Doubly Linked List Dictionary...  (( I made a new pytest, and ran the same tests on this version. it all passed )). I wasn't too thrilled with using that word, because it makes me feel like maybe, I'm a bit unsophisticated...  then I thought, no...  being genuine and having less sophistication,  there is nothing wrong with that.

There are billions if not trillions of people on this planet... it takes all kinds to make society work, one is not worth more then another.  In the end, skynet get's us all.  Or the zombie Apocalypse... double tap that shit.



from ex17DLList import*
from SLList import*
from random import randint

class Dictionary(object):
    def __init__(self, num_buckets=256):
        """Create a place to keep tons of unidentifiable data."""
        # what are they going to store? How much?
        # you'd think it'd be better to add lists as you go.... fill one up to a certain
        # limit first.... There's some shit though about they add stuff to these things
        # crazy amounts at a time.... So imagine the truck shows up with 50 data(s) of stuff
        # to be added to the warehouse at a time... or 500 (tuples)=data
        # warehouse needs to be able to handle the trucks comming in.
        self.warehouse = DLList()
     
        for i in range(0, num_buckets):
            ##  Put a 256 Empty containers into that warehouse
            ##  We can't have the data running around the warehouse....  data, and especially Nodes,
            ## they love to run off if they aren't contained in something.  They gone!  
          
            self.warehouse.push(SLList())

    def hash_key(self, key):
        """
           I thought this was magic. It's not.... hash is using a math formula to get a 
           crazy number for a string.... if it's a string, and modulo is just going to 
           divide that crazy number by 256 and return a whole number remainder. it will be
           between 0 and 255.  the index's of the original warehouse doubly linked list.
        """
        # This is basically step 4 of putting something into the dictionary.... 
        # none of it can keep going without each other's returns. 
        # if key is an integer.... it just gives back that integer % self.count()
        #print(f"key = ({key}) : list = {hash(key) % 2}") # running test

        return hash(key) % self.warehouse.count()
     
     
    # I thought about changing all the buckets to container, but the term bucket is used in 
    # the actual hash tables, so good to keep in, like the hash_key, probably should keep map too...

    def get_bucket(self, key):
        """Set the container's id, and get the python object from the warehouse"""
        ## this is step 3 of setting a tuple into the dictionary...
        ## see  the self.hash_key(key)?   next ones going to use this get_bucket....
        ## wait for it....
        ### set the bucket_id  by using the magical math... pick a number with hash and modulo.
        ### between 0-255. set it to bucket_id
        bucket_id = self.hash_key(key)  ## bucket ( container ) Single linked list
        return self.warehouse.get(bucket_id) ### this returning the python object id of container
     
     
    def get_slot(self, key, default=None):
        """
        This gets the node.... the tuple(data) from the container and the
         the container( Singly linked list) or,   None, None.... if by some chance 
         the warehouse has No containers,  there will be no data(tuple to return either.) 
        """     
        bucket = self.get_bucket(key)
        ## step 2 ... giving us the python object to use... the SLList .... we can activate it, 
        ## use it with that python object id.

        if bucket: # basically, if python object id exists....
            node = bucket.begin # start the list...
         

            while node:
                # this thing... node.value[0]:
                # the node.value here is a tuple,  ( 'spam', 'eggs')
                # you can ask it for node.value[0] = 'spam'
                # or for node.value[1] = 'eggs'  
                # its a positional thing.  I want the thing at position 0. 
                # kinda feels like you could just map out the whole thing some way like this.... 
                if key == node.value[0]: ## if node has key in it
                    return bucket, node ## return node and the bucket... the list we got from warehouse
                else:
                    node = node.next ## continue till it finds the key, or None... 
                 

        # fall through... key not found, or Nothing found... None, None....
        return bucket, None

    def get(self, key, default=None):
        """Gets the value in a bucket for the given key or default."""
        ##  ok , the original has the default of None. I couldn't get it to do anything.
        ## I tried entering it with the key... I tried entering it below... as far as I can tell
        ## get_slot does not give a shite what the default is either...
        ## and this does not return it.  Hell if I know what that's for.
        ## there were some i=0, and i += 0 stuff too in here I took out... far as i can tell they didn't
        ## do a damned thing...  found out later, it's a hint for another exercise!
        bucket, node = self.get_slot(key, default=default)
        ## bucket is the SLList  the hash_key selected for the key/value pair
        ### returns the tuple,  Position,   remember, node.value('spam', 'eggs')
        ## return the node, and eggs, or node. mostly we just want eggs. yummy edible eggs.
        return node and node.value[1] or node

    def set(self, key, value):
        """Sets the key to the value, replacing any existing value."""
        ###  get_slot  did the work above to return bucket and slot...  if slot was None...
        ### key not found  
        ## We got the container from the warehouse,  maybe a matching tuple(data)!
        bucket, slot = self.get_slot(key)
        ## if there was no bucket or slot... set does nothing... it will just fart sunshine all day.


        ### below this line.... the rest of sets steps 4+
        if slot:
            # the key exists, replace it
            # if we have a matching tuple ( key, value )
            # toss that crap out.... we can't have duplicates in the warehouse!
            slot.value = (key, value)
            #  I do this in pytests.... just don't forget to erase them or take em out...
            # not sure what the etiquette is on leaving the commented testing code stuff in is...
            # pytest return
            return 'replace'  #  pytest <-----
        else:
            # the key does not, append to create it
            # the tuple is pushed onto the list.
            #  put that data,  tuple into our container!!!   it 's good to go.... we wait for the
            # next tuple to come in,  and then look up where it goes. 
            bucket.push((key, value))
            # pytest return
            return 'setting' # <---- pytest

    def delete(self, key):
        """
            Detaches node from the Warehouse's container.
            Get the SLList, match the key, and take out the node. 
            The box with the tuple in it. 
        """
        # going through the warehouse, finding the container, matching my
        # key to the box that has the tuple in it, making sure I got the right key (tuple) from that
        # container, take it out of the warehouse.  Gone.
        container = self.get_bucket(key)
        # container = SSList
        node = container.begin
        print("delete")
        while node:
            k = node.value[0] # the node value is a tuple['spam']
            if key == k:
                container.detach_node(node)
                print("diction, detach node")     
                break
            else:
                print(" else block ")
                ## my book code is missing this bit.  I'm not sure why...
                node = node.next
                ## I guess it would be really hard to get more then one thing in a list to 
                ## try it out .... and know what list it's in.... oh.... wait... 
                ## YUP!  this is necessary.
    def list(self):
        """Prints out what's in the Warehouse."""
        warehouselist = self.warehouse.begin
        #  ok... bucket .... is the list... we want to see the nodes...
        # self.warehouse.dump()

        while warehouselist:
            # we go through the warehouse(DLList) and make a list
            # of the items in each collection ...  (SLList)
            # we'll call the SLList's the isle.   
            # go to isle ,   get each node....  the node's value is our tuple
            # print each one... move on to the next isle until we've gone through the
            # whole warehouse.   
            
            isle = warehouselist.value.begin
            while isle:
                # warehouse's node.value is the SLLlist....
                # isle's node.value is the tuples
                print(isle.value)
                isle = isle.next
            warehouselist = warehouselist.next

    def count(self):
        """ should be just like list, Made this for testing purposes """
        #bucket is the container in the warehouse
        # just the same as list.  I interchanged the container and isle. 
        # we count the contents (count += 1) instead of printing the node.value
        warehouse_list = self.warehouse.begin
        count = 0
        while warehouse_list:
            container = warehouse_list.value.begin
           
            # if node exists, increment count by 1
            while container:
                count += 1
                container = container.next
            warehouse_list = warehouse_list.next
            # who doesn't love taking an inventory!!! 

        return count


#  I changed the num_buckets to 2,  and made this bit to fill the list up to 
# check out the delete() methods 'else' block.
#spammy = Dictionary()
#for x in range(0, 30):
    # this put about half in one list and half in the other.
    # hash(key) just returns the integer if it's not a string.
    # modulo by two... will return 1 for odd , 0 for even.
    #spammy.set(x, 'Boomchackalaka.') 
#spammy.list()
#spammy.delete(17)
#spammy.list()












Comments

Popular posts from this blog

JavaScript Ascii animation with while loops and console.log

playing with trigonometry sin in pygame

JavaScript and a Matrix