I have a function that creates a list of aminoacids (aaCandidates), but this list can even be empty. If this list is empty I would like to jump the step and continue with the following one.
My code is:
def magicfunction(referenceDistance,referenceAA):
amminoacids = ('A', 'R', 'N', 'D', 'C', 'Q', 'E', 'G', 'H', 'I', 'L', 'K', 'M', 'F', 'P', 'S', 'T', 'W', 'Y', 'V')
aaCandidates = list()
for aa in amminoacids:
if distance(aa,referenceAA) == referenceDistance:
aaCandidates.append(aa)
if not aaCandidates:
break
luckyAA = choice(aaCandidates)
return(luckyAA)
I call this function in another file as follow:
for i in range(lenghtPairs):
r1 = randrange(20)
r2 = randrange(20)
coppie.append([aminoacidi[r1], aminoacidi[r2]])
for i in range(lenghtPairs):
dictionary = dict()
frequenze = dict()
if i == 0:
a = randrange(20)
b = randrange(20)
pairs[0] = [aminoacids[a], aminoacids[b]]
else:
c = randrange(20)
pairs[i][0] = aminoacids[c]
distanceNeighbours = distance(pairs[i][0],pairs[i-1][0])
aaChosen = magicfunction(distanceNeighbours,pairs[i-1][1])
pairs[i][1] = aaChosen
print(i + 1)
I tried the condition => if not aaCandidates: break but it didn't work:
File "/.../lib/python3.4/random.py", line 255, in choice
raise IndexError('Cannot choose from an empty sequence')
IndexError: Cannot choose from an empty sequence
Your list is empty, so random.choice() fails. You'll need to decide what to do instead when the list is empty, but do so outside of the for loop, so when the list has completed building:
for aa in amminoacids:
if distance(aa,referenceAA) == referenceDistance:
aaCandidates.append(aa)
if not aaCandidates:
return 'some default choice'
luckyAA = choice(aaCandidates)
return luckyAA
All that putting your break in the loop achieves is to ensure that nothing is going to be added to your list if the first aa was not a candidate.
Related
I have a nested list of tens of millions of lists (I can use tuples also). Each list is 2-7 items long. Each item in a list is a string of 1-5 characters and occurs no more than once per list. (I use single char items in my example below for simplicity)
#Example nestedList:
nestedList = [
['a', 'e', 'O', 'I', 'g', 's'],
['w', 'I', 'u', 'O', 's', 'g'],
['e', 'z', 's', 'I', 'O', 'g']
]
I need to find which lists in my nested list contain a pair of items so I can do stuff to these lists while ignoring the rest. This needs to be as efficient as possible.
I am using the following function but it seems pretty slow and I just know there has to be a smarter way to do this.
def isBadInList(bad, checkThisList):
numChecks = len(list) - 1
for x in range(numChecks):
if checkThisList[x] == bad[0] and checkThisList[x + 1] == bad[1]:
return True
elif checkThisList[x] == bad[1] and checkThisList[x + 1] == bad[0]:
return True
return False
I will do this,
bad = ['O', 'I']
for checkThisList in nestedLists:
result = isBadInList(bad, checkThisList)
if result:
doStuffToList(checkThisList)
#The function isBadInList() only returns true for the first and third list in nestedList and false for all else.
I need a way to do this faster if possible. I can use tuples instead of lists, or whatever it takes.
nestedList = [
['a', 'e', 'O', 'I', 'g', 's'],
['w', 'I', 'u', 'O', 's', 'g'],
['e', 'z', 's', 'I', 'O', 'g']
]
#first create a map
pairdict = dict()
for i in range(len(nestedList)):
for j in range(len(nestedList[i])-1):
pair1 = (nestedList[i][j],nestedList[i][j+1])
if pair1 in pairdict:
pairdict[pair1].append(i+1)
else:
pairdict[pair1] = [i+1]
pair2 = (nestedList[i][j+1],nestedList[i][j])
if pair2 in pairdict:
pairdict[pair2].append(i+1)
else:
pairdict[pair2] = [i+1]
del nestedList
print(pairdict.get(('e','z'),None))
create a value pair and store them into map,the key is pair,value is index,and then del your list(this maybe takes too much memory),
and then ,you can take advantage of the dict for look up,and print the indexes where the value appears.
I think you could use some regex here to speed this up, although it will still be a sequential operation so your best case is O(n) using this approach since you have to iterate through each list, however since we have to iterate over every sublist as well that would make it O(n^2).
import re
p = re.compile('[OI]{2}|[IO]{2}') # match only OI or IO
def is_bad(pattern, to_check):
for item in to_check:
maybe_found = pattern.search(''.join(item))
if maybe_found:
yield True
else:
yield False
l = list(is_bad(p, nestedList))
print(l)
# [True, False, True]
Hey so I have a polyalphabetic cipher and it's working great but I am running into the issue of having all my inputs on one line. The inputs would be the shift;secretWord; and message. I need to find a way to check if an input is solely a negative number and if it is I need the code to exit. I also need to find a way to make my code keep looping until the negative condition is met.
alpha = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
shiftChange = 0
secretWord = 0
da_message = 0
shiftChange = int(shiftChange)
inputs = []
shiftChange, secretWord, da_message = input('').split(";")
da_message = da_message.lower()
inputs.append(shiftChange)
inputs.append(secretWord)
inputs.append(da_message)
secretWord = secretWord.lower()
secretWord = secretWord * len(da_message)
cypherText = ''
symbol = ' '
count = 0
for letter in da_message:
if letter in alpha:
shift = alpha.index(secretWord[count]) + int(shiftChange)
letterIndex = alpha.index(letter) + 1
cypherLetter = alpha[(letterIndex+shift)%26]
cypherText = cypherText + cypherLetter
count = count + 1
print(cypherText.upper())
Use int().
The int() raises a ValueError for anything that isn't, entirely, an integer. Trap this error using a try-except loop and then if the error is raised, then execute the rest of your code. (since it is an alphanumeric) Otherwise, compare it if it is less than 0 and exit if true.
Below is a modified version of your code that solves both of your problems.
The while True ensures the program continues to loop until the negative number is found, which in turn causes it to exit the entire program.
alpha = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
shiftChange = 0
secretWord = 0
da_message = 0
cypherText = ''
symbol = ' '
count = 0
shiftChange = int(shiftChange)
inputs = []
while True:
shiftChange, secretWord, da_message = input('enter:').split(";")
da_message = da_message.lower()
inputs.append(shiftChange)
inputs.append(secretWord)
inputs.append(da_message)
secretWord = secretWord.lower()
secretWord = secretWord * len(da_message)
for i in range(len(inputs)):
try:
temp = int(inputs[i])
except ValueError:
for letter in da_message:
if letter in alpha:
shift = alpha.index(secretWord[count]) + int(shiftChange)
letterIndex = alpha.index(letter) + 1
cypherLetter = alpha[(letterIndex+shift)%26]
cypherText = cypherText + cypherLetter
count = count + 1
print(cypherText.upper())
if temp < 0:
exit()
Hope this helps!
I need something like this
accepted_string: An apple a day keeps the doctor away
resultant_string: Aapedyepteotrwy
And for this I have written this code:
accepted_string = input("enter")
add = ''
for count in range(0, len(accepted_string), 2):
if accepted_string[count] == " ":
count += 1
add = add + accepted_string[count]
else:
add = add + accepted_string[count]
print(add)
But this is giving me different output while passing the above sample input. The logic is also correct, then where is the error? I have to skip to next character whenever I encounter a whitespace. Please help me as I am new to this
Simple string slicing with prior replacement:
>>> s = "An apple a day keeps the doctor away"
>>> s.replace(" ", "")[::2]
'Aapedyepteotrwy'
you can remove space before hands instead of doing in for loop and make it list to convert in into array
Code:
accepted_string = input("enter")
add = ''
accepted_string = list(accepted_string.replace(" ", ""))
print(accepted_string)
for count in range(0, len(accepted_string), 2):
add = add + accepted_string[count]
print(add)
output:
['A', 'n', 'a', 'p', 'p', 'l', 'e', 'a', 'd', 'a', 'y', 'k', 'e', 'e', 'p', 's', 't', 'h', 'e', 'd', 'o', 'c', 't', 'o', 'r', 'a', 'w', 'a', 'y']
Aapedyepteotrwy
2nd code:
accepted_string = input("enter")
add = ''
char_count = 1
for count in range(0, len(accepted_string)):
if accepted_string[count] != " ":
char_count += 1
if char_count % 2 == 0:
add = add + accepted_string[count]
# add = add + accepted_string[count]
# else:
# add = add + accepted_string[count]
print(add)
output:
Aapedyepteotrwy
I've written a program that attempts to find a series of letters (toBeFound - these letters represent a word) in a list of letters (letterList), however it refuses to acknowledge the current series of 3 letters as it counts the 'I' in the first list twice, adding it to the duplicate list.
Currently this code returns "incorrect", when it should return "correct".
letterList= ['F','I', 'I', 'X', 'O', 'R', 'E']
toBeFound = ['F', 'I', 'X']
List = []
for i in toBeFound[:]:
for l in letterList[:]:
if l== i:
letterList.remove(l)
List.append(i)
if List == toBeFound:
print("Correct.")
else:
print("Incorrect.")
letterList and toBeFound are sample values, the letters in each can be anything. I can't manage to iterate through the code and successfully ensure that duplicates are ignored. Any help would be greatly appreciated!
Basically, you're looking to see if toBeFound is a subset of letterList, right?
That is a hint to use sets:
In [1]: letters = set(['F','I', 'I', 'X', 'O', 'R', 'E'])
In [2]: find = set(['F', 'I', 'X'])
In [3]: find.issubset(letters)
Out[3]: True
In [4]: find <= letters
Out[4]: True
(BTW, [3] and [4] are different notations for the same operator.)
I think this would solve your problem. Please try it and let me know
letterList= ['F','I', 'I', 'X', 'O', 'R', 'E']
toBeFound = ['F', 'I', 'X']
found_list = [i for i in toBeFound if i in letterList]
print("Correct" if toBeFound == found_list else "Incorrect")
You could make the initial list a set, but if you want to look up a word like 'hello' it wont work because you'll need both l's.
One way to solve this is to use a dictionary to check and see how we are doing so far.
letterList = ['H', 'E', 'L', 'X', 'L', 'I', 'O']
toBeFound = ['H', 'E', 'L', 'L', 'O']
# build dictionary to hold our desired letters and their counts
toBeFoundDict = {}
for i in toBeFound:
if i in toBeFoundDict:
toBeFoundDict[i] += 1
else:
toBeFoundDict[i] = 1
letterListDict = {} # dictionary that holds values from input
output_list = [] # dont use list its a reserved word
for letter in letterList:
if letter in letterListDict: # already in dictionary
# if we dont have too many of the letter add it
if letterListDict[letter] < toBeFoundDict[letter]:
output_list.append(letter)
# update the dictionary
letterListDict[letter] += 1
else: # not in dictionary so lets add it
letterListDict[letter] = 1
if letter in toBeFoundDict:
output_list.append(letter)
if output_list == toBeFound:
print('Success')
else:
print('fail')
How about this: (I tested in python3.6)
import collections
letterList= ['F','I', 'I', 'X', 'O', 'R', 'E']
toBeFound = ['F', 'I', 'X']
collections.Counter(letterList)
a=collections.Counter(letterList) # print(a) does not show order
# but a.keys() has order preserved
final = [i for i in a.keys() if i in toBeFound]
if final == toBeFound:
print("Correct")
else:
print("Incorrect")
If you're looking to check if letterList has the letters of toBeFound in the specified order and ignoring repeating letters, this would be a simple variation on the old "file match" algorithm. You could implement it in a non-destructive function like this:
def letterMatch(letterList,toBeFound):
i= 0
for letter in letterList:
if letter == toBeFound[i] : i += 1
elif i > 0 and letter != toBeFound[i-1] : break
if i == len(toBeFound) : return True
return False
letterMatch(['F','I', 'I', 'X', 'O', 'R', 'E'],['F', 'I', 'X'])
# returns True
On the other hand, if what you're looking for is testing if letterList has all the letters needed to form toBeFound (in any order), then the logic is much simpler as you only need to "check out" the letters of toBeFound using the ones in letterList:
def lettermatch(letterList,toBeFound):
missing = toBeFound.copy()
for letter in letterList:
if letter in missing : missing.remove(letter)
return not missing
As requested.
letterList= ['F','I', 'I', 'X', 'O', 'R', 'E']
toBeFound = ['F', 'I', 'X']
List = []
for i in toBeFound[:]:
for l in set(letterList):
if l== i:
List.append(i)
if List == toBeFound:
print("Correct.")
else:
print("Incorrect.")
This prints correct. I made the letterList a set! Hope it helps.
One simple way is to just iterate through toBeFound, and look for each element in letterList.
letterList= ['F','I', 'I', 'X', 'O', 'R', 'E']
toBeFound = ['F', 'I', 'X']
found = False
for x in letterList:
if x not in toBeFound:
found = False
break
if found:
print("Correct.")
else:
print("Incorrect.")
I am reading a file with about 13,000 names on it into a list.
Then, I look at each character of each item on that list and if there is a match I remove that line from the list of 13,000.
If I run it once, it removes about half of the list. On the 11th run it seems to cut it down to 9%. Why is this script missing results? Why does it catch them with successive runs?
Using Python 3.
with open(fname) as f:
lines = f.read().splitlines()
bad_letters = ['B', 'C', 'F', 'G', 'H', 'J', 'L', 'O', 'P', 'Q', 'U', 'W', 'X']
def clean(callsigns, bad):
removeline = 0
for line in callsigns:
for character in line:
if character in bad:
removeline = 1
if removeline == 1:
lines.remove(line)
removeline = 0
return callsigns
for x in range (0, 11):
lines = clean(lines, bad_letters)
print (len(lines))
You are changing (i.e., mutating) the lines array while you're looping (i.e. iterating) over it. This is never a good idea because it means that you are changing something while you're reading it, which leads to you skipping over lines and not removing them in the first go.
There are many ways of fixing this. In the below example, we keep track of which lines to remove, and remove them in a separate loop in a way so that the indices do not change.
with open(fname) as f:
lines = f.read().splitlines()
bad_letters = ['B', 'C', 'F', 'G', 'H', 'J', 'L', 'O', 'P', 'Q', 'U', 'W', 'X']
def clean(callsigns, bad):
removeline = 0
to_remove = []
for line_i, line in enumerate(callsigns):
for b in bad:
if b in line:
# We're removing this line, take note of it.
to_remove.append(line_i)
break
# Remove the lines in a second step. Reverse it so the indices don't change.
for r in reversed(to_remove):
del callsigns[r]
return callsigns
for x in range (0, 11):
lines = clean(lines, bad_letters)
Save the names you want to keep in a separate list.. Maybe this way:-
with open(fname) as f:
lines = f.read().splitlines()
bad_letters = ['B', 'C', 'F', 'G', 'H', 'J', 'L', 'O', 'P', 'Q', 'U', 'W', 'X']
def clean(callsigns, bad):
valid = [i for i in callsigns if not any(j in i for j in bad)]
return valid
valid_names = clean(lines,bad_letters)
print (len(valid_names))