Hash Function in Python generating error - python

So I am trying to get a grasp on Hash Functions and how exactly they work. I have the following code but I keep getting an error when I try and run the code.
import sys
def part_one():
foo = open('input_table.txt')
for line in foo:
id, make, model, year = line.split(",")
print(make, model)
tuple_list = (make+model,)
return tuple_list
def hash_one(num_buffers, tuple_list):
#part_one()
# A being the first constant prime number to multiply by
# B being the prime number that we add to A*sum_of_chars
tuple_list = part_one()
A = 3
B = 5
count = 0
for item in tuple_list:
for char in item:
# sum_of_chars is the total of each letter in the word
count = ord(char)
count = count + tuple_list
index = ((A * sum_of_chars + B)) % num_buffers
return index
if __name__ == '__main__':
input_table = sys.argv[1]
num_buffers = int(sys.argv[2])
chars_per_buffer = int(sys.argv[3])
sys.argv[4] = 'make'
sys.argv[5] = 'model'
lst = []
for item in range(4, len(sys.argv)):
lst.append(sys.argv[item])
print(lst)
hash_one(lst)
What is wrong with my code that is causing the error? Can anyone help me?

1
You're calling hash() with no arguments, you have to hash something.
A hash of a number will just return the same number though, so it's not very interesting. It's for hashing things like strings.
2
part_one returns nothing, therefore when you call tuple_list = part_one(), it's value is set to None, and you can't iterate though it.
3
Passing in a list through an argument then overwriting it doesn't make any sense anyway. If you want to return a list then use a return statement.
4
It's odd to set argument variables in code, they're for reading things from the command line.
5
(Not an error, but...)
You can use a slice (lst = sys.argv[4:]) as an easier way to get a sub-section of a list.

Related

Partition list of tuples based on a value within each tuple

I am trying to sort a set of data in to 2 separate lists, fulltime and parttime. But it doesn't seem to be working. Can somebody point to where I'm getting this wrong?
data = [(['Andrew'], ['FullTime'], [38]),
(['Fred'], ['PartTime'], [24]),
(['Chris'], ['FullTime'], [38])]
def sort(var1, datadump):
positionlist = []
for b in range(0, len(datadump)):
temp2 = datadump[b][1]
if (temp2 == var1):
positionlist.append(datadump[b])
return (positionlist)
FullTimeList = sort("FullTime", data)
PartTimeList = sort("PartTime", data)
print(FullTimeList)
print(PartTimeList)
This is solved by altering
if (temp2 == var1):
to
if (temp2[0] == var1):
This is because the elements within each tuple are lists holding a string, not the strings themselves.
This problem could also be solved using two list comprehensions:
FullTimeList = [x for x in data if x[1][0] == 'FullTime']
PartTimeList = [x for x in data if x[1][0] == 'PartTime']
Not an answer: just a suggestion. Learn how to use the python debugger.
python -m pdb <pythonscript.py>
In this case, set a breakpoint on line 9
b 9
Run the program
c
When it breaks, look at temp2
p temp2
It tells you
['FullTime']
Look at var1
p var1
It tells you
'FullTime'
And there is your problem.
You'll get a better understanding if you name your variables and functions with descriptive names:
data = [(['Andrew'], ['FullTime'], [38]),
(['Fred'], ['PartTime'], [24]),
(['Chris'], ['FullTime'], [38])]
def filter_records(value, records):
result = []
for i in range(len(records)): # i and j are usual variable names for indices (b is not)
record = records[i]
name, work, hours = record # give names to the parts
if work[0] == value: # work[0] since the values are lists (no need for parenthesis)
result.append(record)
return result # no need for parenthesis
FullTimeList = filter_records("FullTime", data)
PartTimeList = filter_records("PartTime", data)
the pattern:
for i in range(len(records)):
record = records[i]
is an anti-pattern in Python - meaning that there is a better way to write it:
for record in records:
...

Confusing syntax from a search tree algorithm

I am currently taking 6.00.2x from MITx, and there is a line from a search tree algorithm that confuses me, could anyone help please?
val, taken = maxVal(foods, maxUnits)
This syntax does not make sense to me. maxVal is a function, so presumably foods and maxUnits are inputs. But what are val and taken, what does this line do? Nowhere in the code are there variables instantiated with those names, so I am just not sure what they are (and this line of syntax means).
PS: The complete code is as follows. The aforementioned syntax occurs on 3rd line of the function testMaxVal. foods is a list of 1) food, 2) values, and 3) calories.
def maxVal(toConsider, avail):
"""Assumes toConsider a list of items, avail a weight
Returns a tuple of the total value of a solution to the
0/1 knapsack problem and the items of that solution"""
if toConsider == [] or avail == 0:
result = (0, ())
elif toConsider[0].getCost() > avail:
#Explore right branch only
result = maxVal(toConsider[1:], avail)
else:
nextItem = toConsider[0]
#Explore left branch
withVal, withToTake = maxVal(toConsider[1:],
avail - nextItem.getCost())
withVal += nextItem.getValue()
#Explore right branch
withoutVal, withoutToTake = maxVal(toConsider[1:], avail)
#Choose better branch
if withVal > withoutVal:
result = (withVal, withToTake + (nextItem,))
else:
result = (withoutVal, withoutToTake)
return result
def testMaxVal(foods, maxUnits, printItems = True):
print('Use search tree to allocate', maxUnits,
'calories')
val, taken = maxVal(foods, maxUnits)
print('Total value of items taken =', val)
if printItems:
for item in taken:
print(' ', item)
testMaxVal(foods, 750)
As you can see, maxVal can return two outputs at the same time like at the line :
result = (withoutVal, withoutToTake)
Recover these two outputs in two variable val and taken is done by the line :
val, taken = maxVal(foods, maxUnits)
The function maxVal returns a tuple. You can return multiple values from a function in python in the form of tuple.
Example:
def connect():
connection = _connect()
message = "Connected"
if not connection:
message = "Not connected"
return connection, message
connection, message = connect()
maxVal returns a pair.
You can "deconstruct" any tuple by assigning its elements to the appropriate number of variables simultaneously.
Example:
>>> a,b,c = (1,2, "hello")
>>> a
1
>>> b
2
>>> c
'hello'

python list is not copying

In the following subset problem, I'm trying to make a copy of a list object
def findFourPlus(itemCount, seq, goal):
goalDifference = float("inf")
closestPartial = []
subset_sum(itemCount, seq, goal, goalDifference, closestPartial, partial=[])
print(closestPartial)
def subset_sum(itemCount, seq, goal, goalDifference, closestPartial, partial):
s = sum(partial)
# check if the partial sum is equals to target
if(len(partial) == itemCount):
if s == goal:
print(partial)
else:
if( abs(goal - s) < goalDifference):
goalDifference = abs(goal - s)
print(goalDifference)
print(partial)
print(closestPartial)
closestPartial = copy.deepcopy(partial)
for i in range(len(seq)):
n = seq[i]
remaining = seq[i+1:]
subset_sum(itemCount, remaining, goal, goalDifference, closestPartial, partial + [n])
in the subset function, I am trying to make a copy of the partial list to closestPartial. I've tried
closestPartial = partial
closestPartial = list[:]
closestPartial = list(partial)
closestPartial = copy.copy(partial)
closestPartial = copy.deepcopy(partial)
but in the end all of them seems to be futile. closestPartial remains to be an empty list (which is what I initiated to) for some reason
You are passing closestPartial in as a parameter, so the only thing that will work is an inplace update of its list. All of the examples you give replace the list that was in closestPartial with a new list. But since it wasn't the list you passed in, it doesn't update the real list.
Try:
closestPartial[:] = partial
You can get a feel for the problem by printing the list id before and after the operation.
print id(closestPartial)
...some operation
print id(closestPartial)
if the id changes, that means you created a new list and didn't update the one passed in.
EDIT
Seems I need a better explanation... when you call subset_sum, it creates a local variable called closestPartial that references whatever was passed in as a parameter, in this case a list known to the caller as closestPartial. You now have two variables pointing to the same list. If you reassign the variable, like in closestPartial = partial, those two variables now point to different lists. You didn't update the caller's pointer, you just changed the local variable. Instead, if you don't reassign, changes you make to the one list referenced by both variables are seen by the caller as well - because its the same list.
I suspect that your goalDifference is suffering from the same problem, if you change it in a function and then expect the changed value to somehow get back to the calling function.
Here's some (Python 2 style) code to illustrate what's happening:
#! /usr/bin/env python
def testA(update_func):
seq = []
num = 1
for _ in range(5):
newnum = update_func(seq, num)
print 'testA: ', num, seq, newnum
print
def testB(update_func):
seq = []
num = 1
for _ in range(5):
num = update_func(seq, num)
print 'testB: ', num, seq
print
def update0(seq, num):
#This creates a new list
seq = seq + [num]
num = num + 1
print 'update0:', num, seq
return num
def update1(seq, num):
#This updates the existing list
seq.append(num)
num += 1
print 'update1:', num, seq
return num
def update2(seq, num):
#This updates the existing list
seq[:] = seq + [num]
num += 1
print 'update2:', num, seq
return num
def update3(seq, num):
#This updates the existing list
seq += [num]
num += 1
print 'update2:', num, seq
return num
update_funcs = (update0, update1, update2, update3)
for f in update_funcs:
testA(f)
print '------\n'
for f in update_funcs:
testB(f)
Stack Overflow member Ned Batchelder's article Facts and myths about Python names and values has a good explanation, with cute diagrams.

How to count the number of letters in a string with a list of sample?

value = 'bcdjbcdscv'
value = 'bcdvfdvdfvvdfvv'
value = 'bcvfdvdfvcdjbcdscv'
def count_letters(word, char):
count = 0
for c in word:
if char == c:
count += 1
return count
How to count the number of letters in a string with a list of sample? I get nothing in my python shell when I wrote the above code in my python file.
There is a built-in method for this:
value.count('c')
functions need to be called, and the return values need to be printed to the stdout:
In [984]: value = 'bcvfdvdfvcdjbcdscv'
In [985]: count_letters(value, 'b')
Out[985]: 2
In [987]: ds=count_letters(value, 'd') #if you assign the return value to some variable, print it out:
In [988]: print ds
4
EDIT:
On calculating the length of the string, use python builtin function len:
In [1024]: s='abcdefghij'
In [1025]: len(s)
Out[1025]: 10
You'd better google it with some keywords like "python get length of a string" before you ask on SO, it's much time saving :)
EDIT2:
How to calculate the length of several strings with one function call?
use var-positional parameter *args, which accepts an arbitrary sequence of positional arguments:
In [1048]: def get_lengths(*args):
...: return [len(i) for i in args]
In [1049]: get_lengths('abcd', 'efg', '1234567')
Out[1049]: [4, 3, 7]
First you should probably look at correct indenting and only send in value. Also value is being overwritten so the last one will be the actual reference.
Second you need to call the function that you have defined.
#value = 'bcdjbcdscv'
#value = 'bcdvfdvdfvvdfvv'
value = 'bcvfdvdfvcdjbcdscv'
def count_letters(word, char):
count = 0
for c in word:
if char == c:
count += 1
return count
x = count_letters(value, 'b')
print x
# 2
This should produce the result you are looking for. You could also just call:
print value.count('b')
# 2
In python, there is a built-in method to do this. Simply type:
value = 'bcdjbcdscv'
value.count('c')

Why doesn't my function to swap variables swap variables?

First, I have this function:
def change_pos(a, b):
temp = a
a = b
b = temp
print 'Done'
And I call it in another function but it just print 'Done' and do nothing.
I write the code directly:
a = 1
b = 2
temp = a
a = b
b = temp
It works fine. Any suggestion here?
Second, this is my code
def check_exception(list):
for element in list:
# Take list of numbers
# \s*: Skip space or not (\t\n\r\f\v), \d: Number [0-9]
# ?: Non-capturing version of regular parentheses
first = re.compile("\s*(?:\[)(\d+)\s*(?:,)").findall(element)
last = re.compile("\s*(?:,)(\d+)\s*(?:\])").findall(element)
# Convert string to integer
first_int = map(int, first)
last_int = map(int, last)
# Check and code above works
i = 0
print first_int[i]
change_pos(first_int[i],first_int[i+1])
print first_int[i+1]
print len(first_int)
#print type(first_int[0])
# Sort
# Error: list index out of range at line 47 and more
i = 0
while i < len(first_int):
if first_int[i] > first_int[i+1]:
change_pos(first_int[i], first_int[i+1])
change_pos(last_int[i], last_int[i+1])
i += 1
# Check exception
j = 0
while j < len(last_int):
if last_int[j] < first_int[j+1]:
return false
break
else:
j += 1
continue
return true
And I see: IndexError: list index out of range at conditions after # Error
Thanks for any help. :)
Your change_pos function does nothing useful as it only swaps the variables inside the function, not the variables that was used to call the function. One method of accomplishing what you want is this:
def change_pos(a, b):
print 'DONE'
return b, a
and then using it becomes:
a, b = change_pos(a,b)
Or even without a function:
a, b = b, a
Secondly, I'm sure you can figure out why you're getting an index error on your own. But here's why anyways. Arrays are zero indexed and you are using the length of last_int in your while loop. Now imagine last_int has a length of 5. That means it has index values ranging from 0-4. In the last iteration of the loop you are attempting to access last_int[5] in your if statement (last_int[j+1]) which of course will give you an index error.
You may have been told that variables are locations in memory with data in it. This is not true for Python. Variables are just names that point to objects.
Hence, you can not in Python write a function such as the change_pos function you attempt to write, because the names you change will be the names used in the function, not the names used when calling.
Instead of this:
a = 1
b = 2
change_pos(a, b)
You will have to do this:
a = 1
b = 2
a, b = change_pos(a, b)
The function needs to look like this:
def change_pos(a, b):
return b, a
This give you a hint that there is an easier way, and indeed there is. You can do this:
a = 1
b = 2
a, b = b, a
So no need for a function at all.
Since you actually want to swap integers in a list, you can make a function like this:
def change_pos(lst, p):
lst[p], lst[p+1] = lst[p+1], lst[p]
But I don't think that adds significantly the the readability of the code.
Also your usage of this is prefixed with the comment #sort. But your code does not sort. It's a bit like a half-assed bubble sort, but I don't know why you would want to do that.
Numbers are immutable in python. His when you pass them to a function, the function works with copies of the variables. This can be tricky if you try this with mutable types like Lists. But python has this function covered with some neat syntax tricks.
a, b = b, a
This swaps two variables with no need for any additional functions.

Categories