I'm building a slot machine simulator in Python. I have setup the reels as follows:
Reels = [[10,9,4,5,7,4,9,2,6,7,3,4,9,3,4,9,6,5,4,11,8,9,11,2,4,1,9,10,4,9,10,6,4,9,1,5,4,9,1,10,3,8,6,4,9,1,8],
[4,3,5,4,3,5,2,8,4,1,8,10,1,2,9,8,11,2,8,5,6,11,3,4,2,8,4,7,6,10,8,7,9,4,1,6,8,4,2,9,8,3,5,4,10,8],
[1,9,4,2,5,1,6,9,2,5,9,2,10,9,4,8,9,11,2,5,8,9,10,4,1,10,9,2,10,5,9,7,5,6,8,9,7,3,10,6,2,9,5,8,3,1,10,3],
[8,10,3,8,7,3,9,8,10,11,3,10,9,6,8,10,11,6,5,3,8,1,4,9,5,8,1,4,3,8,1,5,9,10,8,3,9,4,3,8,9,4,6,11,3,8,9,7,10,11],
[4,11,1,6,3,9,5,10,9,5,8,11,10,3,1,4,10,3,9,4,7,3,9,10,4,3,1,5,10,6,5,8,4,6,9,1,5,10,8,9,5,4,6,8,9,4,8,5,7,9]]
Now I need to iterate through them from 1 through 5 and build a 3X5 matrix. I want to start by producing a random number that determines where on that reel to stop. That value will be the middle value on that reel. Then, I need to add the top and bottom values (but have to account for the middle number potentially being at the beginning or end of the reel strip. I'm getting the error "list index out of range" on the if StopValue == Reels[i][len(Reels[i])]: line:
def spin():
SpinValues = [[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]]
for i, object in enumerate(Reels):
length = len(Reels[i])
StopValue = random.randint(0,length)
SpinValues[i][1] = Reels[i][StopValue]
if StopValue == 0:
SpinValues[i][0] = Reels[i][len(Reels[i])]
else:
SpinValues[i][0] = Reels[i][StopValue - 1]
if StopValue == Reels[i][len(Reels[i])]:
SpinValues[i][2] = Reels[i][0]
else:
SpinValues[i][2] = Reels[i][StopValue +1]
print(SpinValues)
spin()
Initially I thought I could do this with just "for i in reels," but I read a post here suggesting to use the "for index, object in enumerate(Reels)" method.
len(Reels[i]) is not a valid index for Reels[i]. The last valid index is len(Reels[i]) - 1
To refer to the last item in a list called my_list, you must use
my_list[-1]
or
my_list[len(my_list)-1]
and not:
my_list[len(my_list)]
The reason is that in Python, all indexing starts from 0, and not from 1
I'm new to programming and python and I'm looking for a way to distinguish between two input formats in the same input file text file. For example, let's say I have an input file like so where values are comma-separated:
5
Washington,A,10
New York,B,20
Seattle,C,30
Boston,B,20
Atlanta,D,50
2
New York,5
Boston,10
Where the format is N followed by N lines of Data1, and M followed by M lines of Data2. I tried opening the file, reading it line by line and storing it into one single list, but I'm not sure how to go about to produce 2 lists for Data1 and Data2, such that I would get:
Data1 = ["Washington,A,10", "New York,B,20", "Seattle,C,30", "Boston,B,20", "Atlanta,D,50"]
Data2 = ["New York,5", "Boston,10"]
My initial idea was to iterate through the list until I found an integer i, remove the integer from the list and continue for the next i iterations all while storing the subsequent values in a separate list, until I found the next integer and then repeat. However, this would destroy my initial list. Is there a better way to separate the two data formats in different lists?
You could use itertools.islice and a list comprehension:
from itertools import islice
string = """
5
Washington,A,10
New York,B,20
Seattle,C,30
Boston,B,20
Atlanta,D,50
2
New York,5
Boston,10
"""
result = [[x for x in islice(parts, idx + 1, idx + 1 + int(line))]
for parts in [string.split("\n")]
for idx, line in enumerate(parts)
if line.isdigit()]
print(result)
This yields
[['Washington,A,10', 'New York,B,20', 'Seattle,C,30', 'Boston,B,20', 'Atlanta,D,50'], ['New York,5', 'Boston,10']]
For a file, you need to change it to:
with open("testfile.txt", "r") as f:
result = [[x for x in islice(parts, idx + 1, idx + 1 + int(line))]
for parts in [f.read().split("\n")]
for idx, line in enumerate(parts)
if line.isdigit()]
print(result)
You're definitely on the right track.
If you want to preserve the original list here, you don't actually have to remove integer i; you can just go on to the next item.
Code:
originalData = []
formattedData = []
with open("data.txt", "r") as f :
f = list(f)
originalData = f
i = 0
while i < len(f): # Iterate through every line
try:
n = int(f[i]) # See if line can be cast to an integer
originalData[i] = n # Change string to int in original
formattedData.append([])
for j in range(n):
i += 1
item = f[i].replace('\n', '')
originalData[i] = item # Remove newline char in original
formattedData[-1].append(item)
except ValueError:
print("File has incorrect format")
i += 1
print(originalData)
print(formattedData)
The following code will produce a list results which is equal to [Data1, Data2].
The code assumes that the number of entries specified is exactly the amount that there is. That means that for a file like this, it will not work.
2
New York,5
Boston,10
Seattle,30
The code:
# get the data from the text file
with open('filename.txt', 'r') as file:
lines = file.read().splitlines()
results = []
index = 0
while index < len(lines):
# Find the start and end values.
start = index + 1
end = start + int(lines[index])
# Everything from the start up to and excluding the end index gets added
results.append(lines[start:end])
# Update the index
index = end
I'm looping over the below output from a difflib compare of two configuration files:-
[server]
+ # web-host-name = www.myhost.com
+ https-port = 1080
+ network-interface = 0.0.0.0
[process-root-filter]
[validate-headers]
[interfaces]
[header-names]
[oauth]
[tfim-cluster:oauth-cluster]
[session]
+ preserve-inactivity-timeout = 330
[session-http-headers]
what I'm trying to achieve is to parse the diff and only print out headers (items in []) for which the next item in the list starts with +
I have the following code that is running without errors.
for x in range(0, (len(diff) - 1)):
print str(x) #prints index number instead of the content of the line
z = str(diff)[x+1]
if str(x).startswith('+'):
print(x) # prints nothing x contains the index of the line instead of the text
elif str(x).startswith(' [') and z.startswith('+'):
print(x)
The problem is that the index number of the line is being returned in the loop rather than the text in the line.
e.g. print output from
[0]
[1]
[2]
[3]
[4]
I know I must be missing something basic here but can't seem to find the answer after.
for x in range(0, (len(diff) - 1)):
print str(x) #prints index number instead of the content of the line
The reason the index is being printed here is because x is not iterating over the contents of diff, it's iterating over an integer range that is equal to the length of diff. You already have the answer as to why your print is giving the index instead of the string content here, on the very next line: z = str(diff)[x+1]
Calling diff[x] refers to the line of diff at index x, so if you want to print diff's content or refer to it in later lines you need to do the same thing: print str(diff[x])
What you are doing is looping through an x of the range 0 to length of diff - 1.
This will provide you with all integer values between those two integers, e.g.
for x in range(0, 3):
print(str(x) + ' ')
will give you back:
0 1 2 3
So if diff is a list of strings for each new line, to get the line, you can just use :
# iterate through list diff
for x in diff:
print(x)
to print out all of your lines. If you now want to know if its a header before you print it out:
# iterate through list diff
for x in diff:
# test if x is a header
if x.startswith('[') and x.endswith(']'):
print(x)
Please note that none of this code has been tested.
Hope this helps
EDIT:
if diff is not a list of lines but rather one single string, you can use
line_list = diff.split('\n')
to get a list of lines.
EDIT 2:
If you now want to also check the next line within the first iteration, we have to use indexes instead:
# for every index in list diff
for i in range(0, len(diff) - 1):
if diff[i].startswith('[') and diff[i + 1].startswith('+'):
# do something if its a header with following content
elif diff[i].startswith('+'):
# do something if the line is data
thanks to both #pheonix and #rdowell comments above. I've updated the code to the below which now works:-
for i in range(0, len(diff) - 1):
if diff[i].startswith(' [') and diff[i + 1].startswith('+'):
# do something if its a header with following content
print str(diff[i])
elif diff[i].startswith('+'):
# do something if the line is data
print str(diff[i])
This post will be something I'll refer back to as I'm just getting to know what you can and can't do with the different object types in Python
So I have two files/dictionaries I want to compare, using a binary search implementation (yes, this is very obviously homework).
One file is
american-english
Amazon
Americana
Americanization
Civilization
And the other file is
british-english
Amazon
Americana
Americanisation
Civilisation
The code below should be pretty straight forward. Import files, compare them, return differences. However, somewhere near the bottom, where it says entry == found_difference: I feel as if the debugger skips right over, even though I can see the two variables in memory being different, and I only get the final element returned in the end. Where am I going wrong?
# File importer
def wordfile_to_list(filename):
"""Converts a list of words to a Python list"""
wordlist = []
with open(filename) as f:
for line in f:
wordlist.append(line.rstrip("\n"))
return wordlist
# Binary search algorithm
def binary_search(sorted_list, element):
"""Search for element in list using binary search. Assumes sorted list"""
matches = []
index_start = 0
index_end = len(sorted_list)
while (index_end - index_start) > 0:
index_current = (index_end - index_start) // 2 + index_start
if element == sorted_list[index_current]:
return True
elif element < sorted_list[index_current]:
index_end = index_current
elif element > sorted_list[index_current]:
index_start = index_current + 1
return element
# Check file differences using the binary search algorithm
def wordfile_differences_binarysearch(file_1, file_2):
"""Finds the differences between two plaintext lists,
using binary search algorithm, and returns them in a new list"""
wordlist_1 = wordfile_to_list(file_1)
wordlist_2 = wordfile_to_list(file_2)
matches = []
for entry in wordlist_1:
found_difference = binary_search(sorted_list=wordlist_2, element=entry)
if entry == found_difference:
pass
else:
matches.append(found_difference)
return matches
# Check if it works
differences = wordfile_differences_binarysearch(file_1="british-english", file_2="american-english")
print(differences)
You don't have an else suite for your if statement. Your if statement does nothing (it uses pass when the test is true, skipped otherwise).
You do have an else suite for the for loop:
for entry in wordlist_1:
# ...
else:
matches.append(found_difference)
A for loop can have an else suite as well; it is executed when a loop completes without a break statement. So when your for loop completes, the current value for found_difference is appended; so whatever was assigned last to that name.
Fix your indentation if the else suite was meant to be part of the if test:
for entry in wordlist_1:
found_difference = binary_search(sorted_list=wordlist_2, element=entry)
if entry == found_difference:
pass
else:
matches.append(found_difference)
However, you shouldn't use a pass statement there, just invert the test:
matches = []
for entry in wordlist_1:
found_difference = binary_search(sorted_list=wordlist_2, element=entry)
if entry != found_difference:
matches.append(found_difference)
Note that the variable name matches feels off here; you are appending words that are missing in the other list, not words that match. Perhaps missing is a better variable name here.
Note that your binary_search() function always returns element, the word you searched on. That'll always be equal to the element you passed in, so you can't use that to detect if a word differed! You need to unindent that last return line and return False instead:
def binary_search(sorted_list, element):
"""Search for element in list using binary search. Assumes sorted list"""
matches = []
index_start = 0
index_end = len(sorted_list)
while (index_end - index_start) > 0:
index_current = (index_end - index_start) // 2 + index_start
if element == sorted_list[index_current]:
return True
elif element < sorted_list[index_current]:
index_end = index_current
elif element > sorted_list[index_current]:
index_start = index_current + 1
return False
Now you can use a list comprehension in your wordfile_differences_binarysearch() loop:
[entry for entry in wordlist_1 if not binary_search(wordlist_2, entry)]
Last but not least, you don't have to re-invent the binary seach wheel, just use the bisect module:
from bisect import bisect_left
def binary_search(sorted_list, element):
return sorted_list[bisect(sorted_list, element)] == element
With sets
Binary search is used to improve efficiency of an algorithm, and decrease complexity from O(n) to O(log n).
Since the naive approach would be to check every word in wordlist1 for every word in wordlist2, the complexity would be O(n**2).
Using binary search would help to get O(n * log n), which is already much better.
Using sets, you could get O(n):
american = """Amazon
Americana
Americanization
Civilization"""
british = """Amazon
Americana
Americanisation
Civilisation"""
american = {line.strip() for line in american.split("\n")}
british = {line.strip() for line in british.split("\n")}
You could get the american words not present in the british dictionary:
print(american - british)
# {'Civilization', 'Americanization'}
You could get the british words not present in the american dictionary:
print(british - american)
# {'Civilisation', 'Americanisation'}
You could get the union of the two last sets. I.e. words that are present in exactly one dictionary:
print(american ^ british)
# {'Americanisation', 'Civilisation', 'Americanization', 'Civilization'}
This approach is faster and more concise than any binary search implementation. But if you really want to use it, as usual, you cannot go wrong with #MartijnPieters' answer.
With two iterators
Since you know the two lists are sorted, you could simply iterate in parallel over the two sorted lists and look for any difference:
american = """Amazon
Americana
Americanism
Americanization
Civilization"""
british = """Amazon
Americana
Americanisation
Americanism
Civilisation"""
american = [line.strip() for line in american.split("\n")]
british = [line.strip() for line in british.split("\n")]
n1, n2 = len(american), len(british)
i, j = 0, 0
while True:
try:
w1 = american[i]
w2 = british[j]
if w1 == w2:
i += 1
j += 1
elif w1 < w2:
print('%s is in american dict only' % w1)
i += 1
else:
print('%s is in british dict only' % w2)
j += 1
except IndexError:
break
for w1 in american[i:]:
print('%s is in american dict only' % w1)
for w2 in british[j:]:
print('%s is in british dict only' % w2)
It outputs:
Americanisation is in british dict only
Americanization is in american dict only
Civilisation is in british dict only
Civilization is in american dict only
It's O(n) as well.
Is it possible to do the following in python?
i=1
while True:
w = open("POSCAR_i","w")
i=i+1
if i<10:
break
So Basically, it should create POSCAR_1 through POSCAR_10.
Thank you.
It is much more pythonic (and all around better) to use a for loop:
for idx in range(1,11):
f = open("POSCAR_%d" % idx, "w")
f.close()
You can also use the format() method, which is now officially preferred, although the % operator is still much more common in the wild.
The problem is that your break statement was executed on the first iteration.
The i variable is indeed less than 10 - so the loop terminates.
What you would need to do is something like this:
i = 1
while True:
w = open("POSCAR_%d" % i, "w")
w.close()
i += 1
if i == 10:
break
Don't forget to close the file object once you have finished with it (which in this case is immediately).
You could also just put the termination condition in the loop's definition:
i = 1
while i <= 10:
w = open("POSCAR_%d" % i, "w")
w.close()
i += 1
You would use str.format to pass in i as a variable:
w = open("POSCAR_{}".format(i),"w")
If you wanted 1 - 10, a for loop would do the same.
for i in range(1,11):
w = open("POSCAR_{}".format(i),"w")
But w will be reassigned each time.
You need to use if i==10 or your loop will end straight away as i is < 10 initially
You can use i <=10 as the condition and remove the if statement:
i=1
while i <= 10:
with open("POSCAR_{}".format(i),"w") as w: # with will close your files automatically
i+=1
Almost correct
i=1
while True:
w = open("POSCAR_%d" % i,"w")
i=i+1
if i>10:
break
will work
Basically the answer is no. Here is some information regarding why it is not possible and also some polishing.
There are a couple of problems regarding your code:
the line w = open("POSCAR_i","w") creates a file with the name of POSCAT_i. The i is perceived as a part of a string. You should construct such a string via using w = open("POSCAR_%d" % i, "w") instead of w = open("POSCAR_i","w").
The if executes the first time because its condition is met. As in the first iteration, i = 1, the condition i < 10 is met so break is executed. Change the if condition to i > 10.
Also it would b a good practice to use for loop instead of while loop. In this case, you would not an if block anymore.
It is also a good practice to close the file handle before using it for other purposes. Or an even better practice is using different file handles.
So I would write the code in this way:
# Previous codes
.
.
.
Files = [];
for i in range(1,11):
w = open("POSCAR_%d" % i, "w");
Files.append(w);
# Rest of the code
.
.
.
for w in Files:
w.close();
# End of code
Enjoy!