0

I'm trying to solve this newbie puzzle:

I've created this function:

def bucket_loop(htable, key):
    bucket = hashtable_get_bucket(htable, key)
    for entry in bucket:
        if entry[0] == key:          
            return entry[1]                         
    return None

And I have to call it in two other functions (bellow) in the following way: to change the value of the element entry[1] or to append to this list (entry) a new element. But I can't do that calling the function bucket_loop the way I did because "you can't assign to function call" (assigning to a function call is illegal in Python). What is the alternative (most similar to the code I wrote) to do this (bucket_loop(htable, key) = value and hashtable_get_bucket(htable, key).append([key, value]))?

def hashtable_update(htable, key, value):
    if bucket_loop(htable, key) != None:
        bucket_loop(htable, key) = value
    else:
        hashtable_get_bucket(htable, key).append([key, value])

def hashtable_lookup(htable, key):
    return bucket_loop(htable, key)

Thanks, in advance, for any help!

This is the rest of the code to make this script works:

def make_hashtable(size):
    table = []
    for unused in range(0, size):
        table.append([])
    return table

def hash_string(s, size):
    h = 0
    for c in s:
         h = h + ord(c)
    return h % size

def hashtable_get_bucket(htable, key):
    return htable[hash_string(key, len(htable))]

Similar question (but didn't help me): SyntaxError: "can't assign to function call"

Community
  • 1
  • 1
craftApprentice
  • 2,697
  • 17
  • 58
  • 86
  • Have you considered making it a class and defining `__getitem__()` and `__setitem__()`? – Ignacio Vazquez-Abrams Mar 26 '12 at 05:18
  • 1
    I'm a little unclear with your first bit of code. You have a loop with an if else statement so it will only do one loop. Do you only want to check the first element in bucket or do you want to check all the elements in bucket? – Jeff Mar 26 '12 at 05:26
  • Hi Ignacio Vazquez-Abrams, I'm not suppose to use class in this procedure (I'm not learned this concept yet). But thank you very much for the tip. – craftApprentice Mar 26 '12 at 12:43
  • Hi, @Jeff, I want to check all the elements in bucket untill I find one that satisfy the condition. Thanks for your attention! – craftApprentice Mar 26 '12 at 12:44

3 Answers3

2

In general, there are three things you can do:

  1. Write “setter” functions (ex, bucket_set)
  2. Return mutable values (ex, bucket_get(table, key).append(42) if the value is a list)
  3. Use a class which overrides __getitem__ and __setitem__

For example, you could have a class like like:

class Bucket(object):
    def __setitem__(self, key, value):
        # … implementation …
    def __getitem__(self, key):
        # … implementation …
        return value

Then use it like this:

>>> b = Bucket()
>>> b["foo"] = 42
>>> b["foo"]
42
>>> 

This would be the most Pythonic way to do it.

David Wolever
  • 148,955
  • 89
  • 346
  • 502
  • Thanks, David, for the best awnswer! I'm still with doubt how to change the value of a list (in this case, entry[1] is a list) like this "bucket_loop(htable, key) = value", but your suggestion helped me. Instead of bucket_loop(htable, key) return entry[1], it now returns entry (wich is also a list) and I assigned a new value to entry this way in hashtable_update(htable, key, value): "entry[1] = value". But If there was a way to do this returning entry[1] (and not entry), it'd be better). – craftApprentice Mar 26 '12 at 13:23
  • You can use `bucket_lookup(htable, key)[0] = 42` if `bucket_lookup` returns a list (you could also, do, say, `bucket_lookup(htable, key).name = "John"` if `bucket_lookup` returned a `Person`). This is because, in this case, you are assigning to *a field of* the object returned by `bucket_lookup`, you aren't assigning *directly to the object*. – David Wolever Mar 26 '12 at 16:51
1

One option that would require few changes would be adding a third argument to bucket_loop, optional, to use for assignment:

empty = object() # An object that's guaranteed not to be in your htable
def bucket_loop(htable, key, value=empty):
    bucket = hashtable_get_bucket(htable, key)
    for entry in bucket:
        if entry[0] == key:
           if value is not empty: # Reference (id) comparison
                entry[1] = value
            return entry[1]
        else: # I think this else is unnecessary/buggy
            return None

However, a few pointers:

  1. I agree with Ignacio Vazquez-Abrams and David Wolever, a class would be better;

  2. Since a bucket can have more than one key/value pairs, you shouldn't return None if the first entry didn't match your key. Loop through all of them, and only return None in the end; (you can ommit this statement also, the default behavior is to return None)

  3. If your htable doesn't admit None as a value, you can use it instead of empty.

mgibsonbr
  • 21,755
  • 7
  • 70
  • 112
-1

So you're basically cheating at udacity, which is an online cs class / university? Funny part is you couldn't even declare the question properly. Next time cheat thoroughly and paste the two functions you're supposed to simplify and request someone simplify them by creating a third function with the overlapping code within. Doesn't matter anyway because if this is the one you need help in you're likely not doing very well in the class

you were also able to solve the problem without using most of these tools, it was an exercise in understanding how to identify an handle redundancies, NOT efficiency...

Real instructions:

Modify the code for both hashtable_update and hashtable_lookup to have the same behavior they have now, but using fewer lines of code in each procedure.  You should define a new procedure, helper, to help with this.  Your new version should have approximately the same running time as the original version, but neither hashtable_update or hashtable_lookup should include any for or while loop, and the block of each procedure should be no more than 6 lines of code

Seriously, cheating is lame.

Lame
  • 1