Most straightforward alternative to a while loop in python - python

The general point of the program is to search for words and make sure that they occur in the right order.
I am currently using the code
while not corpus[index_F2-1] == corpus[index_B]:
index_F2 = corpus.index(corpus[index_F2], index_F2+1)
in order to search for a word, check to make sure that a given word appears before it, and find a different instance of the same word in the corpus if the word does not appear in the correct environment. The only problem with this code is that, if the conditions are never met, it returns an error. Rather than having it return an error, it would be better if it could exit the loop, and then assign a new value to "F2" in order to try again. The obvious way to make the program exit the loop would be to use a while loop, but I am unsure how to get a while loop to not find a new value for F2 if the current one works. In short, it would work best if the script ran in this order.
Check to see if the current F2 will ever work
If it will not work, assign a new value to F2.
Check again recurse and check to see if the new F2 will work
and so on
An if statement would probably be in order, but exactly where and how it would work, I am unsure. Also, the code for reassigning F2 already exists. It is
index_E2= corpus.index(corpus[index_E2], index_E2+1)
index_F = index_E2+1
index_F2 = corpus.index(corpus[index_F], index_F+1)
A future problem that could present itself is that the corpus may run out of F2 values ( as a result of running out of E2 values) and display a similar error, but that is another issue.

I think I might understand what you're looking for. It sounds like you want to have multiple nested loops, with an exit point within the innermost loop. The most obvious way to achieve this, in my mind, is to enclose the loops within a function. Since all this corpus stuff is confusing, I'll use a simple example:
words_to_find = ['tree', 'cow', 'lots_of_other_words']
words_to_search = ['bathtub', 'more_words']
def find_words(words_to_search, words_to_find):
for i, fword in enumerate(words_to_find):
for j, sword in enumerate(words_to_search):
if fword == sword:
return (fword, i, j)
You can nest as many loops as you like here -- for, while, whatever -- and still break out of all of them easily once you've found what you want.
Let me know if that doesn't answer your question.
EDIT: I suppose if you wanted to have it all in one while loop you could do this:
word_list = ['blah', 'blah2', 'etc']
word_list2 = ['other', 'words']
i = 0
j = 0
while True:
if i == len(word_list):
i = 0
j += 1
elif thing_I_want(word_list[i], word_list2[j]):
do_something()
break
else:
i += 1

Related

looping on iterables, return best practice

Every now and then I fall on this pattern when looping through an array:
for a in b:
if a==y:
#do somethinng
return 1
there is no else statement because I need to check the full array for a==y (let's say a is name in a dir list) before returning anything.
It would also be a good idea to return something only if no element in the array fulfills the condition a==y
How should I re organize the code in this sense?
How do I tell the caller if the loop doesn't 'succeed' in finding 'y'?
If you are expecting to encounter y only once or only take into account its first occurrence (given that you have a return statement within the condition), then here's another method:
if any(a == y for a in b):
#do something
return 1
else:
return 0
It would probably be a good idea to return something only if no element in the array fulfills the condition x==b but I don't know how to re organize the code in this sense.
The usual thing is to put the return reflecting the fact that nothing matched after the loop:
for a in b:
if a==y:
#do somethinng
return 1
return 0 # or whatever
In some cases, it may be appropriate to throw an exception after the loop instead, if the fact that nothing matched within the loop is an exceptional condition, not a normal case.
Please be sure to check out navneethc's answer using any as well.

Trouble with top down recursive algorithm

I am trying to make word chains, but cant get around recursive searching.
I want to return a list of the words reuired to get to the target word
get_words_quicker returns a list of words that can be made by just changing one letter.
def dig(InWord, OutWord, Depth):
if Depth == 0:
return False
else:
d = Depth - 1;
wordC = 0;
wordS = [];
for q in get_words_quicker(InWord):
wordC+=1
if(OutWord == q):
return q
wordS.append(q)
for i in range(0,wordC):
return dig(wordS[i],OutWord,d)
Any help/questions would be much appreciated.
ANALYSIS
There is nowhere in your code that you form a list to return. The one place where you make a list is appending to wordS, but you never return this list, and your recursive call passes only one element (a single word) from that list.
As jasonharper already pointed out, your final loop can iterate once and return whatever the recursion gives it, or it can fall off the end and return None (rather than "nothing").
You have two other returns in the code: one returns False, and the other will return q, but only if q has the same value as OutWord.
Since there is no code where you use the result or alter the return value in any way, the only possibilities for your code's return value are None, False, and OutWord.
REPAIR
I'm afraid that I'm not sure how to fix this routine your way, since you haven't really described how you intended this code to carry out the high-level tasks you describe. The abbreviated variable names hide their purposes. wordC is a counter whose only function is to hold the length of the list returned from get_words_quicker -- which could be done much more easily.
If you can clean up the code, improve the data flow and/or documentation to something that shows only one or two disruptions in logic, perhaps we can fix the remaining problems. As it stands, I hesitate to try -- you'd have my solution, not yours.

How can a for-loop that touches no important code change program output?

I'm working on a relatively large python file, and am working on adding in the next important feature. However, I've noticed that inserting ANY for loop is changing the program's output.
To test this, I put in the following loop:
for fff in range(2):
print 'test'
The variable fff appears nowhere else in the code. Output is iterated through a list called trueRepeats, which clearly is not touched by this code (nor is any variable, for that matter). And yet, no matter where in the code I put this loop -- even before trueRepeats is declared; even if it's the first code that is executed after the imports, the output changes.
EDIT: Here is the full source: BitBucket. The original location where I tried to add the loop was under comment block #4, but as mentioned, it seemed to cause an issue in a variety of other places. I'm running on the file "example.py" also in the repository. Without the loop, the program returns two repeats, at lines {4, 7} and {1, 10}. With the loop, it returns instances at {2, 3} and {1, 10}.
I know this is not much code to go off of, but before I can diagnose what the issue is, I don't even have a clue how this is possible, which is my question: What in python would make it so that an independent for-loop can be affecting output that only involves variables that the loop doesn't touch?
EDIT 2: When I talk about the output changing, I am not talking about the two "test" lines printed out by the loop. These could be replaced by pass but I felt print would have fewer side effects.
EDIT 3: Upon further investigation, this problem runs much deeper than a for loop, and thus this question is probably not well-suited for StackOverflow, since the real question seems to be much less focused. Commenting out the line:
if flag == 5:
print "TEST: " + str(key)
Also changed program output, as did commenting out just a section of a line, which just appended the literal + "Parent: " to the end of a string that was being printed. Side effects like adding a literal to a string do not seem normal, so I'm going to need to investigate further to figure out why python is behaving so strangely.
No matter what the rest of your code is, that loop will print out "test" twice.
Why? Because for loops don't need a variable, "fff" is just a placeholder to iterate through.
I could have this code:
def add(a, b):
print a + b
add(5, 5)
for fff in range(2):
print "test"
And the output would be:
10testtest
I think this is the bug in your code:
alphaset = set() ## 1
...
for i in range(len(partition)):
for j in range(len(partition[i])):
alphaset.add(type(partition[i][j])) ## 2
nodecount += 1
...
count = 0
mapping = dict()
for elem in alphaset: ## 3
mapping[elem] = count ## 4
count+=1
alphasize = count
...
for i in range(len(partition)):
j = len(partition) - i - 1
...
for v in range(len(partition[j])):
node = partition[j][v]
SV = list()
SV.append(mapping[type(node)]) ## 5
Here's what happening. At 1, you have a set that is filled at 2 with some types that are taken from a list with a specific "order." Then, at 3 and 4, you iterate over the set and map each element in the set to some number. Then, at 5, that number is added to a list. If I understood your code correctly, the rest of the code depends on the "order" of the elements in that list, which depends on the mapping, which in itself depends on the order of the elements in the set at 1.
Now, there are no guarantees of the order of the elements in a set nor of the iteration order over it. So, at 3 and 4, and for different runs, you will get different mappings.
The solution is to either explicitly sort the set into a list, or use an OrderedSet which preserves insertion order (assuming the code before point 1 always inserts the nodes in the same order).

python small crosswords for beginners

my_str="ellezagchickenbndodetballigatoraaaolmeznacattleeblrctacfenarcesssadlritfhftrarrssos aoiarefaareppohssarghcerumrheirmmwildfcumeboimltaairfovindalbiglalobehoeasiaxuesabldinbbccrhhrtylrlahsifdlogkrctlaiareogoldfinchefnnddmneepoletnarntadodinosauroxofoeclictnahpelepalgaierhohcaorkcocyatrmoacrflamingoerefafloechateehchdracaribou"
def create_2d_list(N):
output_list=[]
counter=0
for row in range(0,N):
temp=[]
for col in range(0,N):
temp.append(my_str[counter])#you can add a charcter instead of counter
counter=counter+1
output_list.append(temp[:])
return output_list
N=18
x=create_2d_list(N)
for row in range(0,N):
total=0
s="|"
for col in range(0,N):
my_str="{0:2} ".format(x[row][col])
s=s+my_str+"|"
print "-"*(N*4+1)
print s,
print " "
the_valid_words=open("E:/asd/words.txt","r").readlines()
def looking_word_left_to_right(the_list):
for any_words in the_valid_words:
for every in x[0]:
the_first_index=x[0].index(every)
for every in range(the_first_index,(the_first_index)+7):
c=str(every)
the_join=" ".join(c)
if the_join==the_valid_words:
word.upper().replace(every,x[0].upper(every))
return x[0]
print looking_word_left_to_right(x)
every time i run the program, the looking_word_left_to_right doesn't print anything
P.S its similar to small crossword for beginners, Capitalizing the letters that make a word and removing every other letter without changing places, if someone could give like thoughts on how to proceed that would be great. i have certain valid words to look for.
and i'm a newbie so go easy on me :)
appreciate the help.
There seem to be a number of problems.
Why are you operating on x when you also pass it in as the_list" Just use the_list.
You're only looking at the first line of x and never moving beyond that.
It looks like you're putting a space between every character before you compare. If c = "abcdefg" then " ".join(c) will give you "a b c d e f g". If your the_valid_words doesn't have spaces in it, then if the_join==the_valid_words will always evaluate to false.
You're comparing to the_valid_words, which is your entire list. You should probably be comparing to EACH valid word using any_word... which you aren't using anywhere else.
You may also be running into a problem with iterating over x, while you're changing it (it will sometimes invalidate the iterator... but sometimes not). I.e. if you're iterating through x and then you change x before you're done iterating, then Python might not know where the iterator belongs in the new version of x. Since the_list is the same as x anyway, it might be better to do for every in the_list: and then change x to your heart's content.
It looks like you may not quite understand how for loops work in Python. Take a look at those, and that may help some.

List iteration issue in Python

I am working with Google Python class exercises where I am getting this issue -
def front_x(words):
# +++your code here+++
list = []
for i,s in enumerate(words):
print i,s
if s[0] == 'x':
list.append(words.pop(i))
return list
print front_x(['bbb','ccc','axx','xzz','xaa'])
my loop is only iterating from 0 to 3, so print i,s is giving me values till 'xzz'.Please point where I am wrong.
Don't modify something as you're iterating over it. words.pop(i) modifies words, which you're iterating over via enumerate().
I'd suggest looking at list comprehensions for accomplishing your apparent goal.
Yes, you probably shouldn't words.pop(). The word you want is most likely in s - add that to the list instead.
Also, note that naming a list "list", will more or less erase the "list" builtin type from your local scope. It's not a make or break kind of deal, but it's something pylint would warn about.

Categories