2 different results when expecting the same..why? - python

When running the code, please see below, input is ('Zoe', 14), I get as result 8, running the 'Finding Buckets' code in the Online Python Tutor also with ('Zoe', 14), where "def hash_string" is included, the result is 2 out 2, when that code finished, why? Or, in other words, does the other 2 defs causing that result?
In the 'Finding Buckets' code are 3 def. I exchanged the order of those def - the results are the same-does the order really does not matter?
def hash_string(keyword,buckets):
out = 0
for s in keyword:
out = (out + ord(s)) % buckets
return out
Online Python Tutor "Finding Buckets":
1 def hashtable_get_bucket(table,keyword):
2 return table[hash_string(keyword,len(table))]
3
4 def hash_string(keyword,buckets):
5 out = 0
6 for s in keyword:
7 out = (out + ord(s)) % buckets
8 return out
9
10 def make_hashtable(nbuckets):
11 table = []
12 for unused in range(0,nbuckets):
13 table.append([])
14 return table
15 table = [[['Francis', 13], ['Ellis', 11]], [], [['Bill', 17],
16 ['Zoe', 14]], [['Coach', 4]], [['Louis', 29], ['Rochelle', 4], ['Nick', 2]]]
17 print hashtable_get_bucket(table, "Zoe")
def hashtable_get_bucket(table,keyword):
return table[hash_string(keyword,len(table))]
def hash_string(keyword,buckets):
out = 0
for s in keyword:
out = (out + ord(s)) % buckets
return out
def make_hashtable(nbuckets):
table = []
for unused in range(0,nbuckets):
table.append([])
return table
Here the comment from the notes:
Function hashtable_get_bucket returns the bucket containing the given keyword, from the hash
table, passed in as the first argument.
If you remember structure of a hash table, you will find out that it is composed of n buckets, one of
which needs to be returned by the hashtable_get_bucket function. Index of the bucket, which
would eventually contain the given keyword (in case the keyword will be present in the hash table),
is computed and returned by already defined function hash_string.
The function hash_string will in turn take the keyword and number of buckets as its
arguments. First argument (the keyword) is straightforward, since it was passed directly to
hashtable_get_bucket function by its caller. The second argument (number of buckets) can be
computed using len function on the hashmap (recall how hashmap is composed of n buckets).

Both Functions do exactly the same.
But in the online part hash_string('Zoe', 5) is called and not hash_string('Zoe', 14)
Where dose the 5 come from?
In line 2 there is:
hash_string(keyword, len(table))
with len(tabel) being 5.

Related

Counting mistake in number of different elements in two strings

My code seems to have some sort of error when considering the 'Q' variable in the following code. I know when counted by hand and when looking at the values I should obtain, Q should be equal to 3. In my case, it is equal to 4. Further, it seems like my code is not properly printing the positions in which the characters differ between two strings. I am struggling to solve this.
s1 = 'GAGACTACGACTAGAGCTAGACGGTACAC'
s2 = 'CAGGCCACTACCCGAGTTGGACAGAATAC'
P1=0
P2=0
sites=[]
for i in range(len(s1)):
if s1[i]=='A' and s2[i]=='G':
P2+=1
z=(i+1)
sites.append(z)
if s1[i]=='G' and s2[i]=='A':
P2+=1
z=(i+1)
sites.append(z)
if s1[i]=='C' and s2[i]=='T':
P1+=1
z=(i+1)
sites.append(z)
if s1[i]=='T' and s2[i]=='C':
P1+=1
z=(i+1)
sites.append(z)
P=P1+P2
print('L lenght of sequence:',len(s1))
print('P1 transitional difference between pyrmidines (c-t):',P1,'/',len(s1))
print('P2 transitional difference between purines (a-g):',P2,'/',len(s1))
x=len([i for i in range(len(s1)) if s1[i] != s2[i]])
Q = x-P
print('Q transversions',Q,'/',len(s1),'\n')
print('transitions',(P1+P2))
print('number of different sites',x)
print('locations at which sites differ',sites)
Output:
L lenght of sequence: 29
P1 transitional difference between pyrmidines (c-t): 4 / 29
P2 transitional difference between purines (a-g): 3 / 29
Q transversions 4 / 29
transitions 7
number of different sites 11
locations at which sites differ [4, 6, 12, 17, 19, 23, 27]
Proper values:
The answer here was simply my mistake; the code works completely fine but I simply mistyped a letter in S2.

Timeout Issue in Looping Through Hackerrank Example

can anyone explain why my code for a hacker rank example is timing out. I'm new to whole idea of efficiency of code based on processing time. The code seems to work on small sets, but once I start testing cases using large datasets it times out. I've provided a brief explanation of the method and its purpose for context. But if you could provide any tips if you notice functions I'm using that might consume a large amount of runtime that would be great.
Complete the migratoryBirds function below.
Params: arr: an array of tallies of species of birds sighted by index.
For example. arr = [Type1 = 1, Type2 = 4, Type3 = 4, Type4 = 4, Type5 = 5, Type6 = 3]
Return the lowest type of the the mode of sightings. In this case 4 sightings is the
mode. Type2 is the lowest type that has the mode. So return integer 2.
def migratoryBirds(arr):
# list of counts of occurrences of birds types with the same
# number of sightings
bird_count_mode = []
for i in range(1, len(arr) + 1):
occurr_count = arr.count(i)
bird_count_mode.append(occurr_count)
most_common_count = max(bird_count_mode)
common_count_index = bird_count_mode.index(most_common_count) + 1
# Find the first occurrence of that common_count_index in arr
# lowest_type_bird = arr.index(common_count_index) + 1
# Expect Input: [1,4,4,4,5,3]
# Expect Output: [1 0 1 3 1 0], 3, 4
return bird_count_mode, most_common_count, common_count_index
P.S. Thank you for the edit Chris Charley. I just tried to edit it at the same time
Use collections.Counter() to create a dictionary that maps species to their counts. Get the maximum count from this, then get all the species with that count. Then search the list for the first element of one of those species.
import collections
def migratoryBirds(arr):
species_counts = collections.Counter(arr)
most_common_count = max(species_counts.values())
most_common_species = {species for species, count in species_counts if count = most_common_count}
for i, species in arr:
if species in most_common_species:
return i

Nested FOR cycle wih a dictionary. How to start checking the second FOR from the value the first FOR uses

So I have a dictionary in which the tag is the patient code or name(string), and the number associated is the consult time(int). For example I have this:
{'0001': 15, 'Charles': 20} The person '0001' takes 15 minutes in a consult, the person 'Charles' takes 20 minutes.
I do not know in advance where there is a name or a number identifying a person(but they are both strings), that is, I don't know where Charles is located in the dictionary or even if it exists at all
I want to run this dictionary to check the patients that have the same consult time and if they have I want to run a certain function which is not relevant. For now I have this:
for pat_i in self.MD_dict:
for pat_j in self.MD_dict:
if(self.MD_dict[pat_i]==self.MD_dict[pat_j]):
aux=aux+1
funtion(pat_i, pat_j);
However I want j to start from i+1. How do I do that?
I tried using the range fucntion:
for pat_i in range(len(self.MD_dict)):
for pat_j in range(i+1,len(self.MD_dict)):
if(self.MD_dict[pat_i]==self.MD_dict[pat_j]):
aux=aux+1
funtion(pat_i, pat_j);
But because pat_i could be a string this doens't work . For example with pat_i=1 and pat_j=2 the code necessary for the if to work would be '0001' and Charles. But since pat_i!='0001' and pat_j!='Charles' it doesn't work
In the original dictionary, patient name/id is key and time is value. In the new dictionary, time is key and list of paitent name/id is the value.
This is the idea of making a dictionary for inverse look up and then combine patient name/id with the same time into a list.
def make_inverse_dict(x):
# Time is key. List of patients is value
time_dict = {}
for name, time in x.items():
if time in time_dict:
time_dict[time].append(name)
else:
time_dict[time] = [name]
return time_dict
def f(p1, p2):
print(f" {p1}, {p2}")
def make_patient_pair(patient_list):
# Triangular loop to make pairs of patients
# without duplication
n_patients = len(patient_list)
out = []
for i in range(n_patients):
for j in range(i):
pair = (patient_list[i], patient_list[j])
out.append(pair)
return out
def main():
patient_dict = {'0001': 15,
'0002': 10,
'Charles': 20,
'Ann': 20,
'0003': 15}
time_dict = make_inverse_dict(patient_dict)
for time, patient_list in time_dict.items():
n_patients = len(patient_list)
print("time: ", time)
if n_patients > 1:
for p1, p2 in make_patient_pair(patient_list):
f(p1, p2)
main()
result:
time: 15
0003, 0001
time: 10
time: 20
Ann, Charles
The issue with your code is that you are iterating through it more than once. On the second iteration, you then check if MD_dict[pat_i] is equal to MD_dict[pat_j]. This means that you are going to get double the amount of data because at one point, the second loop will reach the same exact point that the first loop is on. For example, when the first loop reaches a value, let's say, "Charles," the second loop will first start at the beginning and then it will eventually reach "Charles." Obviously, the value for "Charles" isn't going to change between the first and second loop - this will result in an instance in which you would be passing "Charles" and "Charles" into your function, which is not what you want.
Let's say MD_dict is:
MD_dict = {'0001': 15, 'Charles': 20, '0002':15, 'Alex': 20, 'Jack':15}
What we can do is use enumerate to make sure these duplicates don't happen:
pats = list(MD_dict.keys())
enum = list(enumerate(pats))
Above, enum pairs the patients' name and the index at which they appear:
[(0, '0001'), (1, 'Charles'), (2, '0002'), (3, 'Alex'), (4, 'Jack')]
Then, we can iterate over enum twice:
for x, pat_i in enum:
for y,pat_j in enum:
if x != y and MD_dict[pat_i] == MD_dict[pat_j]:
function(pat_i, pat_j) # apply function here
Notice how x != y appears in the conditional statement. This is to avoid pairing the same person with itself. This ensures that the second loop will not consider the person that the first loop is on. The result is:
function(0001, 0002) # consult times == 15
function(0001, Jack) # consult times == 15
function(Charles, Alex) # consult times == 20
function(0002, 0001) # consult times == 15
function(0002, Jack) # consult times == 15
function(Alex, Charles) # consult times == 20
function(Jack, 0001) # consult times == 15
function(Jack, 0002) # consult times == 15
However, there is one issue with the function above, and I am not totally clear on what you were asking for in the question. This problem is that the function will be applied to "Charles" and "Alex" and then "Alex" and "Charles" later on. This is because we run through the dictionary twice, so it's going to pick up "Alex" as a match when the first loop hits "Charles" and it will pick up "Charles" as a match when the first loop hits "Alex." If this is not what you want, we can slice enum on the second loop:
pats = list(MD_dict.keys())
enum = list(enumerate(pats))
for x, pat_i in enum:
for y,pat_j in enum[x+1:]:
if MD_dict[pat_i] == MD_dict[pat_j]:
function(pat_i, pat_j) # apply function here
Above, for y,pat_j in enum[x+1:] will only consider the people that follow the person that the first loop is on. We then do not have to check if x != y. The output is as follows:
function(0001, 0002) # consult times == 15
function(0001, Jack) # consult times == 15
function(Charles, Alex) # consult times == 20
function(0002, Jack) # consult times == 15
sorted_items = sorted(self.MD_dict.items(), key=lambda x: x[1])
for i, (pat_i, pat_i_val) in enumerate(sorted_items):
for (pat_j, pat_j_val) in sorted_items[i+1:]
if pat_i_val == pat_j_val:
aux=aux+1
funtion(pat_i, pat_j)

Wrong list output than what was expected

So I have to iterate through this list and divide the even numbers by 2 and multiply the odds by 3, but when I join the list together to print it gives me [0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0]. I printed each value inside the loop in order to check if it was an arithmetic error but it prints out the correct value. Using lambda I have found out that it rewrites data every time it is called, so I'm trying to find other ways to do this while still using the map function. The constraint for the code is that it needs to be done using a map function. Here is a snippet of the code:
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
data_list1 = []
i = 0
while i < len(data):
if (data[i] % 2) == 0:
data_list1 = list(map(lambda a: a / 2, data))
print(data_list1[i])
i += 1
else:
data_list1 = list(map(lambda a: a * 3, data))
print(data_list1[i])
i += 1
print(list(data_list1))1
Edit: Error has been fixed.
The easiest way for me to do this is as follows:
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
data_list1 = []
i = 0
for i in range(len(data)):
if (data[i]%2) == 0:
data_list1=data_list1+[int(data[i]/2)]
elif (data[i]%2) == 1: # alternatively a else: would do, but only if every entry in data is an int()
data_list1=data_list1+[data[i]*3]
print(data_list1)
In your case a for loop makes the code much more easy to read, but a while loop works just as well.
In your original code the issue is your map() function. If you look into the documentation for it, you will see that map() affects every item in the iterable. You do not want this, instead you want to change only the specified entry.
Edit: If you want to use lambda for some reason, here's a (pretty useless) way to do it:
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
data_list1 = []
for i in range(len(data)):
if (data[i] % 2) == 0:
x = lambda a: a/2
data_list1.append(x(data[i]))
else:
y = lambda a: a*3
data_list1.append(y(data[i]))
print(data_list1)
If you have additional design constraints, please specify them in your question, so we can help.
Edit2: And once again onto the breach: Since you added your constraints, here's how to do it with a mapping function:
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def changer(a):
if a%2==0:
return a/2
else:
return a*3
print(list(map(changer,data)))
If you want it to be in a new list, just add data_list1=list(map(changer,data)).
Hope this is what you were looking for!
You can format the string for the output like this:
print(','.join(["%2.1f " % (.5*x if (x%2)==0 else 3*x) for x in data]))
From your latest comment I completely edited the answer below (old version can be found in the edit-history of this post).
From your update, I see that your constraint is to use map. So let's address how this works:
map is a function which exists in many languages and it might be surprising to see at first because it takes a function as an argument. One analogy could be: You give a craftsmen (the "map" function) pieces of metal (the list of values) and a tool (the function passed into "map") and you tell him, to use the tool on each piece of metal and give you back the modified pieces.
A very important thing to understand is that map takes a complete list/iterable and return a new iterable all by itself. map takes care of the looping so you don't have to.
If you hand him a hammer as tool, each piece of metal will have a dent in it.
If you hand him a scriber, each piece of metal will have a scratch in it.
If you hand him a forge as tool, each piece of metal will be returned molten.
The core to underand here is that "map" will take any list (or more precisely an "iterable") and will apply whatever function you give it to each item and return the modified list (again, the return value is not really a list but a new "iterable").
So for example (using strings):
def scribe(piece_of_metal):
"""
This function takes a string and appends "with a scratch" at the end
"""
return "%s with a scratch" % piece_of_metal
def hammer(piece_of_metal):
"""
This function takes a string and appends "with a dent" at the end
"""
return "%s with a dent" % piece_of_metal
def forge(piece_of_metal):
"""
This function takes a string and prepends it with "molten"
"""
return "molten %s" % piece_of_metal
metals = ["iron", "gold", "silver"]
scribed_metals = map(scribe, metals)
dented_metals = map(hammer, metals)
molten_metals = map(forge, metals)
for row in scribed_metals:
print(row)
for row in dented_metals:
print(row)
for row in molten_metals:
print(row)
I have delibrately not responded to the core of your question as it is homework but I hope this post gives you a practical example of using map which helps with the exercise.
Another, more practical example, saving data to disk
The above example is deliberately contrived to keep it simple. But it's not very practical. Here is another example which could actually be useful, storing documents on disk. We assume that we hava a function fetch_documents which returns a list of strings, where the strings are the text-content of the documents. We want to store those into .txt files. As filenames we will use the MD5 hash of the contents. The reason MD5 is chosen is to keep things simple. This way we still only require one argument to the "mapped" function and it is sufficiently unique to avoid overwrites:
from assume_we_have import fetch_documents
from hashlib import md5
def store_document(contents):
"""
Store the contents into a unique filename and return the generated filename.
"""
hash = md5(contents)
filename = '%s.txt' % hash.hexdigest()
with open(filename, 'w') as outfile:
outfile.write(contents)
return filename
documents = fetch_documents()
stored_filenames = map(store_document, documents)
The last line which is using map could be replaced with:
stored_filenames = []
for document in documents:
filename = store_document(document)
stored_filenames.append(filename)

Finding Total of Multiple Hands in Blackjack

I have multiple hands of a Blackjack game.
ex.
Player 1 = ['AD', 'AS']
Player 2 = ['6C', '3D']
Player 3 = ['TD', 'AH']
And I'm trying to get the value of each hand by referencing it to a deck value dictionary:
deckValue = {'AH':11, '2H':2,'3H':3, '4H':4, '5H':5, '6H': 6, '7H': 7, '8H':8,
'9H':9, 'TH':10, 'JH':10, 'QH':10, 'KH':10, 'AC':11, '2C':2,'3C':3,
'4C':4, '5C':5, '6C':6,'7C': 7, '8C':8, '9C':9, 'TC':10, 'JC':10,
'QC':10, 'KC':10, 'AS':11, '2S':2,'3S':3, '4S':4, '5S':5, '6S': 6,
'7S': 7, '8S':8, '9S':9, 'TS':10, 'JS':10, 'QS':10, 'KS':10,
'AD':11, '2D':2,'3D':3, '4D':4, '5D':5, '6D': 6, '7D': 7, '8D':8,
'9D':9, 'TD':10, 'JD':10, 'QD':10, 'KD':10}
Finding a value in a dictionary can be achieved with the
deckvalue.get(key)
or
deckvalue[key]
Where key would be the string in each hand ex. deckvalue.get('AH') = 11
To achieve what I'm trying to do, I'm using a for loop to go through each hand and find the total value.
def calculate_hand(pHands):
# What I have so far
total = 0
for i in pHands:
deckValue.get(pHands[i][0])
deckValue.get(pHands[i][1])
total = #value of 0 + value of 1
return
Where pHands is:
pHands = [['AD', 'AS'], ['6C', '3D'], ['TD', 'AH']]
But I'm getting a 'list indices must be integers, not list' error
I'm new to Python, so I have no clue what this is (but it's probably due to the pHands containing str elements not int elements).
How could I get individual totals for each hand?
eg.
pHands[0] = 22
pHands[1] = 9
pHands[2] = 21
Would I have to assign a new variable to save each hands total to?
Thanks for any input.
If you're iterating over a list, you don't get indices, but actually the list elements. Better:
def calculate_hand(pHands):
# What I have so far
values = []
for (card1, card2) in pHands:
total = deckValue.get(card1) + deckValue.get(card2)
values.append(total)
return values
Also, there's a more concise way to get the value of a card:
def getvalue(card):
val = card[0]
return 11 if val=="A" else 10 if val in "TQKJ" else int(val)
If you have a function like that, you can actually write the whole calculate_hand function in single list comprehension:
def calculate_hand(pHands):
return [getvalue(card1) + getvalue(card2) for (card1, card2) in pHands]

Categories

Resources