Function find() does not recognize letter - python

find() don't work in my code.
I don't know why find() does not recognize letter.
following is my code.
def search(Object, maze_row, letter) :
Object[0] += 1
Object[1] = maze_row.find(letter)
def main() :
row_col = "5 5"
input_maze = "#####\n#..B#\n#.#.#\n#RO.#\n#####"
maze = input_maze.split('\n')
red_ball = [-1,-1]
blue_ball = [-1,-1]
hole = [-1,-1]
for maze_row in maze :
search(red_ball, maze_row,'R')
search(blue_ball, maze_row,'B')
search(hole, maze_row,'O')
if(red_ball[1] >= 0 and blue_ball[1] >= 0 and hole[1] >= 0) :
break
print(red_ball, blue_ball, hole)
if __name__ == '__main__' :
main()
result is ([4, -1], [4, -1], [4, -1])

find() is finding your letter.
However, in subsequent loops of for maze_row in maze it is setting back Object[1] to -1 due to the fact that the element can't be found in the next maze_row.
You can solve this in a variety of ways, with the most concise being to change your search function:
def search(Object, maze_row, letter) :
Object[0] += 1
if Object[1] == -1:
Object[1] = maze_row.find(letter)
Edit: Indentation

There's nothing wrong with find.
The problem is that your code keeps looping over the rows even after you find a match and set the correct index.
The only condition that would break from the loop is when the three letters R, B, O all occurs in the same row, which obviously is impossible.
So when you try to print the three variables, you would see the result for the last row, which contains none of your target letters.
It would be simpler if you create a function to search for the row and column of a letter in a maze:
def search(maze, target):
for i, row in maze:
j = row.find(target)
if j != -1:
return i, j
return -1, -1
red_ball = search(maze, 'R')

Related

Write a function to find the longest common prefix string amongst an array of strings. Index out of range

I am doing a problem where i need to Write a function to find the longest common prefix string amongst an array of strings.
For example :
Input: strs = ["flower","flow","flight"]
Output: "fl"
What I am trying to do, is check each letter indiviudally of each word to see if they are equal. and when they are not then I know that at that moment we have the longest common prefix.After brainstorming for a while, this was the best i could to and went with this idea. However, once I finished my code, it seems to work for some arrays, but most of the time I have an index out of range error. I went to python visualizer to see where I go wrong but everytime I try to change something I get an index error but for a different reason. so after hours of debugging, i gave up and i am now asking for your help to solve this index problem.
for example an index error occurs when i have this array : [ "ab" , "a" ] and more. Im pretty sure my idea is code and my code almost works, so im just asking how to change it, not an entire new code. Thank you
This is my code :
strs = ["ab","a"]
def longestCommonPrefix(strs):
for word in strs:
if word == "":
return ""
if len(strs) == 1:
return strs[0]
common_prefix = ""
j = 0
Common = True
while Common:
for i in range(len(strs) - 1):
if strs[i][j] != strs[i + 1][j]:
Common = False
break
else:
common_prefix += strs[0][j]
j += 1
return common_prefix
print(longestCommonPrefix(strs))
strings = ["a", "ab"]
def find_longest_prefix(data):
shortest_word = min(data, key=len)
for prefix_slice_end in range(len(shortest_word), 0, -1):
if all(i.startswith(shortest_word[0:prefix_slice_end]) for i in data):
return shortest_word[0:prefix_slice_end]
return ''
print(find_longest_prefix(strings))
# >> a
The error is because all strings in the lst do not have the same length, so if you loop over one string length, there might be a chance that some strings have lengths smaller than this. So while using the if condition, try and except block the check for the IndexError.
Try this
strs = ["ab", "a"]
def longestCommonPrefix(strs):
for word in strs:
if word == "":
return ""
if len(strs) == 1:
return strs[0]
common_prefix = ""
j = 0
Common = True
while Common:
for i in range(len(strs) - 1):
try:
if strs[i][j] != strs[i + 1][j]:
Common = False
break
except IndexError:
Common = False
break
else:
common_prefix += strs[0][j]
j += 1
return common_prefix
print(longestCommonPrefix(strs))
If you want some other way then use this one.
def longestCommonPrefix(lst):
for a in range(1, len(lst[0])):
try:
if not all(letter.startswith(lst[0][:a]) for letter in lst[1:]):
return lst[0][:a-1]
except IndexError:
return lst[0][:a-1]
return ""
lst = ["flower", "flow", "flight"]
print(longestCommonPrefix(lst))
def longestCommonPrefix(strs):
if len(strs) == 0:
return ""
current = strs[0]
for i in range(1,len(strs)):
temp = ""
if len(current) == 0:
break
for j in range(len(strs[i])):
if j<len(current) and current[j] == strs[i][j]:
temp+=current[j]
else:
break
current = temp
return current
input_list = ["school","schedule","scotland"]
print(longestCommonPrefix(input_list))

Without using built-in functions, a function should reverse a string without changing the '$' position

I need a Python function which gives reversed string with the following conditions.
$ position should not change in the reversed string.
Should not use Python built-in functions.
Function should be an efficient one.
Example : 'pytho$n'
Result : 'nohty$p'
I have already tried with this code:
list = "$asdasdas"
list1 = []
position = ''
for index, i in enumerate(list):
if i == '$':
position = index
elif i != '$':
list1.append(i)
reverse = []
for index, j in enumerate( list1[::-1] ):
if index == position:
reverse.append( '$' )
reverse.append(j)
print reverse
Thanks in advance.
Recognise that it's a variation on the partitioning step of the Quicksort algorithm, using two pointers (array indices) thus:
data = list("foo$barbaz$$")
i, j = 0, len(data) - 1
while i < j:
while i < j and data[i] == "$": i += 1
while i < j and data[j] == "$": j -= 1
data[i], data[j] = data[j], data[i]
i, j = i + 1, j - 1
"".join(data)
'zab$raboof$$'
P.S. it's a travesty to write this in Python!
A Pythonic solution could look like this:
def merge(template, data):
for c in template:
yield c if c == "$" else next(data)
data = "foo$barbaz$$"
"".join(merge(data, reversed([c for c in data if c != "$"])))
'zab$raboof$$'
Wrote this without using any inbuilt functions. Hope it fulfils your criteria -
string = "zytho$n"
def reverse(string):
string_new = string[::-1]
i = 0
position = 0
position_new = 0
for char in string:
if char=="$":
position = i
break
else:
i = i + 1
j = 0
for char in string_new:
if char=="$":
position_new = i
break
else:
j = j + 1
final_string = string_new[:position_new]+string_new[position_new+1:position+1]+"$"+string_new[position+1:]
return(final_string)
string_new = reverse(string)
print(string_new)
The output of this is-
nohty$x
To explain the code to you, first I used [::-1], which is just taking the last position of the string and moving forward so as to reverse the string. Then I found the position of the $ in both the new and the old string. I found the position in the form of an array, in case you have more than one $ present. However, I took for granted that you have just one $ present, and so took the [0] index of the array. Next I stitched back the string using four things - The part of the new string upto the $ sign, the part of the new string from after the dollar sign to the position of the $ sign in the old string, then the $ sign and after that the rest of the new string.

Finding if string is concatenation of others

I am working on a problem where one must determine if a string is a concatenation of other string (these strings can be repeated in the concatenated strings). I am using backtracking to be as efficient as possible. If the string is a concatenation, it will print the strings it is a concatenation of. If not, it will print NOT POSSIBLE. Here is my python code:
# note: strList has to have been sorted
def findFirstSubstr(strList, substr, start = 0):
index = start
if (index >= len(strList)):
return -1
while (strList[index][:len(substr)] != substr):
index += 1
if (index >= len(strList)):
return -1
return index
def findPossibilities(stringConcat, stringList):
stringList.sort()
i = 0
index = 0
substr = ''
resultDeque = []
indexStack = []
while (i < len(stringConcat)):
substr += stringConcat[i]
index = findFirstSubstr(stringList, substr, index)
if (index < 0):
if (len(resultDeque) == 0):
return 'NOT POSSIBLE'
else:
i -= len(resultDeque.pop())
index = indexStack.pop() + 1
substr = ''
continue
elif (stringList[index] == substr):
resultDeque.append(stringList[index])
indexStack.append(index)
index = 0
substr = ''
i += 1
return ' '.join(resultDeque)
I keep failing the last half of the test cases and can't figure out why. Could someone prompt me in the right direction for any cases that this would fail? Thanks!
First, of all, this code is unnecessary complicated. For example, here is an equivalent but shorter solution:
def findPossibilities(stringConcat, stringList):
if not stringConcat: # if you want exact match, add `and not stringList`
return True
return any(findPossibilities(stringConcat[len(s):],
stringList[:i] + stringList[i+1:]) # assuming non-repeatable match. Otherwise, simply replace with `stringList`
for i, s in enumerate(stringList)
if stringConcat.startswith(s))
Actual answer:
Border condition: remaining part of stringConcat matches some of stringList, search is stopped:
>>> findPossibilities('aaaccbbbccc', ['aaa', 'bb', 'ccb', 'cccc'])
'aaa ccb bb'

Finding A Matching Bracket, Python [duplicate]

This question already has answers here:
Indices of matching parentheses in Python
(5 answers)
Closed 6 years ago.
The Problem:
I am attempting to write some python code that searches through a list and returns the index of a matching bracket. For example:
array = ["(","foo",")","(","bar","(",")",")"]
f(0) => 2
f(1) => ERROR: Not a bracket.
f(2) => 0
f(3) => 7
My Feeble Attempts:
I tried looping through the list and finding the closest bracket, but then I realised it didn't work when you had loops inside loops (loopception). I have also tried adding a counter that adds one to the counter if it's a new bracket ( and takes one if it's a close bracket ), then checks to see if it equals -1, but that doesn't work.
Previous Code:
while True:
if(count == -1):
iterator = j+1
break
else:
j += 1
print j
if(commands[j] == "("):
count += 1
if(commands[j] == ")"):
count -= 1
Where iterator is the input and commands is the array
Assuming the array holds a correct sequence of opening/closing backets:
array = ["(","foo",")","(","bar","(",")",")"]
bracketPositions = []
for i, item in enumerate(array):
if i == 0 and item == ')':
print("Non sense ! Exit")
break
if item == '(':
bracketPositions.append(i)
elif item ==')':
if len(bracketPositions) > 0:
openingPosition = bracketPositions.pop()
print(openingPosition, '-->', i)
else:
print('ERROR: Not a bracket. Word is: %s.' % item)
Prints:
ERROR: Not a bracket (foo).
0 --> 2
ERROR: Not a bracket (bar).
5 --> 6
3 --> 7
With the counter variable you were on the right track, but it's difficult to say what exactly went wrong without seeing the entire code. Basically, what you have to do is: Determine in which direction to go and what to look out for. Initialize the number of matching parens to find as 1, then iterate through the array. If you find the original parens again, increment the counter, if you find the counterpart, decrement the counter. If the counter reaches zero, return the current position.
You can try something like this:
def match(array, pos):
try:
step = {"(": +1, ")": -1} [array[pos]] # go left or right?
other = {"(": ")", ")": "("}[array[pos]] # what to look for?
count = 1 # number of 'other' we have to find
cur = pos # current position
while True:
cur += step # go one step further
if array[cur] == array[pos]: # nested parens
count += 1
if array[cur] == other: # found match (but maybe for nested)
count -= 1
if count == 0: # found match for original parens
return cur
except KeyError:
# not a ( or ) or no match found
return None
array = ["(","foo",")","(","bar","(",")",")"]
print([match(array, i) for i, _ in enumerate(array)])
# [2, None, 0, 7, None, 6, 5, 3]

Iterating and indexing

I am currently stuck with this program. I am attempting to determine the molecular weight of a compound given the molecular equation (only Cs, Hs, and Os). I also am unsure of how to correctly format [index +1], as I am trying to determine what the next character after "x" is to see if it is a number or another molecule
def main():
C1 = 0
H1 = 0
O1 = 0
num = 0
chemicalFormula = input("Enter the chemical formula, or enter key to quit: ")
while True:
cformula = list(chemicalFormula)
for index, x in enumerate(cformula):
if x == 'C':
if cformula[index + 1] == 'H' or cformula[index + 1] == 'O':
C1 += 1
else:
for index, y in range(index + 1, 1000000000):
if cformula[index + 1] != 'H' or cformula[index + 1] != 'O':
num = int(y)
num = num*10 + int(cformula[index + 1])
else:
C1 += num
break
this is the error I keep getting
Enter the chemical formula, or enter key to quit: C2
File "/Users/ykasznik/Documents/ykasznikp7.py", line 46, in main
for index, y in range(index + 1, 1000000000):
TypeError: 'int' object is not iterable
>>>
You should change this line
for index, y in range(index + 1, 1000000000):
to
for y in range(index + 1, 1000000000):
The answers provided here focus on two different aspects of solving your problem:
A very specific solution to your error (int is not iterable), by correcting some code.
A bit bigger perspective of how to handle your code.
Regarding 1, a comment to your question noted the issue: the syntax of tuple-unpacking in your inner loop.
An example of Tuple-unpacking would be
a,b = ['a','b']
Here, Python would take the first element of the right hand side (RHS) and assign it to the first name on the left hand side (LHS), the second element of RHS and assign it to the second name in the LHF.
Your inner loop that faults,
for index, y in range(index + 1, 1000000000),
is equivalent of trying to do
index, y = 1
Now, an integer is not a collection of elements, so this would not work.
Regarding 2, you should focus on the strategy of modularization, which basically means you write a function for each sub-problem. Python was almost born for this. (Note, this strategy does not necessarily mean writing Python-modules for each subproblem.)
In you case, your main goal can be divided into several sub-problems:
Getting the molecular sequences.
Split the sequences into individual sequences.
Splitting the sequence into its H, C, and O-elements.
Given the number of H, C and O-atoms, calculate the molecular weight.
Step 3 and 4 are excellent candidates for independent functions, as their core problem is isolated from the remaining context.
Here, I assume we only get 1 sequence at a time, and that they can be of the form:
CH4
CHHHH
CP4H3OH
Step 3:
def GetAtoms(sequence):
'''
Counts the number of C's, H's and O's in sequence and returns a dictionary.
Only works with a numeric suffices up to 9, e.g. C10H12 would not work.
'''
atoms = ['C','H','O'] # list of which atoms we want to count.
res = {atom:0 for atom in atoms}
last_c = None
for c in sequence:
if c in atoms:
res[c] += 1
last_c = c
elif c.isdigit() and last_c is not None:
res[last_c] += int(c) - 1
last_c = None
else:
last_c = None
return res
You can see, that regardless of how you obtain the sequence and how the molecular weight is calculated, this method works (under the preconditions). If you later need to extend the capabilities of how you obtain the atom-count, this can be altered without affecting the remaining logic.
Step 4:
def MolecularWeight(atoms):
return atoms['H']*1 + atoms['C']*8 + atoms['O']*18
Now your total logic could be this:
while True:
chemicalFormula = input("Enter the chemical formula, or enter key to quit: ")
if len(chemicalFormula) == 0:
break
print 'Molecular weight of', chemicalFormula, 'is', MolecularWeight(GetAtoms(chemicalFormula))
Here's my idea on how to solve the problem. Basically, you keep track of the current 'state' and iterate through each character exactly once, so you can't lose track of where you are or anything like that.
def getWeightFromChemical(chemical):
chemicals = {"C" : 6, "H" : 1, "O" : 8}
return chemicals.get(chemical, 0)
def chemicalWeight(chemicalFormula):
lastchemical = ""
currentnumber = ""
weight = 0
for c in chemicalFormula:
if str.isalpha(c): # prepare new chemical
if len(lastchemical) > 0:
weight += getWeightFromChemical(lastchemical)*int("1" if currentnumber == "" else currentnumber)
lastchemical = c
currentnumber = ""
elif str.isdigit(c): # build up number for previous chemical
currentnumber += c
# one last check
if len(lastchemical) > 0:
weight += getWeightFromChemical(lastchemical)*int("1" if currentnumber == "" else currentnumber)
return weight
By the way, can anyone see how to refactor this to not have that piece of code twice? It bugs me.
Change
for index, y in range(index + 1, 1000000000):
to
for index, y in enumerate(range(index + 1, 1000000000)):
Although you may consider renaming your outer loop or inner loop index for clarity
for index, x in enumerate(cformula):
if x == 'C':
if cformula[index + 1] == 'H' or cformula[index + 1] == 'O':
C1 += 1
else:
for index, y in range(index + 1, 1000000000):
This is a Really Bad Idea. You are overwriting the value of index from the outer loop with the value of index from the inner loop.
You should use a different name, say index2 for the inner loop.
Also, when you say for index, y in range(index + 1, 1000000000): you are acting as if you are expecting range() to produce a sequence of 2-tuples. But range always produces a sequence of ints.
Roger has suggested for y in range(index + 1, 1000000000): but I think you are intending to get the value of y from somewhere else (it's not clear where. Maybe you want to use the second argument of enumerate() to specify the value to start from, instead?
That is,
for index2, y in enumerate(whereeveryoumeanttogetyfrom, index + 1)
so that index2 equals index +1 on the first step through the loop, index +2 on the second, etc.
Range returns either a list of int, or an iterable of int, depending on which version of Python you are using. Attempting to assign that single int into two names causes Python to attempt to iterate through that int in automated tuple unpacking.
So, change the
for index, y in range(index + 1, y):
to
for y in range(index + 1, y):
Also, you use index + 1 repeatedly, but mostly to look up the next symbol in your cformula. Since that doesn't change over the course of your outer loop, just assign it its own name once, and keep using that name:
for index, x in enumerate(cformula):
next_index = index + 1
next_symbol = cformula[next_index]
if x == 'C':
if next_symbol == 'H' or next_symbol == 'O':
C1 += 1
else:
for y in range(next_index, 1000000000):
if next_symbol != 'H' or next_symbol != 'O':
num = y*10 + int(next_symbol)
else:
C1 += num
break
I've also refactored out some constants to make the code cleaner. Your inner loop as written was failing on tuple assignment, and would only be counting up the y. Also, your index would be reset again once you exited the inner loop, so you would be processing all of your digits repeatedly.
If you want to iterate over the substring after your current symbol, you could just use slice notation to get all of those characters: for subsequent in cformula[next_index:]
For example:
>>> chemical = 'CH3OOCH3'
>>> chemical[2:]
'3OOCH3'
>>> for x in chemical[2:]:
... print x
...
3
O
O
C
H
3

Categories

Resources