readlines produces an empty list Python - python

I'm trying to create a game of hangman. When I try to read the file with a list of words it returns an empty array.
Code:
#Making a game of hangman
import random
def rand_word(file_name):
# Retrieves a random word from a file
f = open(file_name, "r")
for num_lines, words in enumerate(f):
pass
num_lines += 1
print(num_lines)
rand_line = random.randint(1,num_lines)
print (rand_line)
file = f.readlines()
print(file)
f.close()
rand_word("words.txt")

You exhausted the file when looping over it in your for loop, so when you use readlines, you're at the end of the file and there's nothing left to read.
You should read your words in a list first, then choose a random one from the list:
import random
def rand_word(filename):
with open(filename) as f:
words = f.readlines()
word = random.choice(words).strip()
return word

Related

How to count elements in a text file?

I am trying to count elements in a text file. I know I am missing an obvious part, but I can't put my finger on it. This is what I currently have which just produces the count of the letter "f" not the file:
filename = open("output3.txt")
f = open("countoutput.txt", "w")
import collections
for line in filename:
for number in line.split():
print(collections.Counter("f"))
break
import collections
counts = collections.Counter() # create a new counter
with open(filename) as infile: # open the file for reading
for line in infile:
for number in line.split():
counts.update((number,))
print("Now there are {} instances of {}".format(counts[number], number))
print(counts)

Getting a random word from a text file

I am trying to return a word from a text file (so that I can eventually make a game from the word) but right now I get the error
IndexError: string index out of range
this is what my text file looks like
yellow
awesome
barking
happy
dancing
laughing
and this is the code I currently have
import random
def generate_the_word(infile):
for line in infile.readlines():
random_line = random.randrange(line[0], line[len(line) + 1])
print(random_line)
def main():
infile = open("words.txt","r")
generate_the_word(infile)
infile.close
main()
Do I have the wrong idea about indexing?
import random
def generate_the_word(infile):
random_line = random.choice(open(infile).read().split('\n'))
return random_line
def main():
infile = "words.txt"
print(generate_the_word(infile))
main()
Your for loop is iterating over every line in the file and indexing into that line. You should also take advantage of Python's context managers, which take care of opening and closing files for you. What you want is to load all the lines:
with open(infile) as f:
contents_of_file = f.read()
Your second problem is that you aren't properly indexing into those lines with randrange. You want a range between 0 and the max number of lines:
lines = contents_of_file.splitlines()
line_number = random.randrange(0, len(lines))
return lines[line_number]
You also need to import the random module before this will run.
Your whole program would look like:
import random
def generate_the_word(infile):
with open(infile) as f:
contents_of_file = f.read()
lines = contents_of_file.splitlines()
line_number = random.randrange(0, len(lines))
return lines[line_number]
def main():
print(generate_the_word("Filename.txt"))
main()
You should also note that reading the file every time is inefficient; perhaps read it once and then pick lines from that. You could, for instance, read it in the main function and pass its already-read values to the generate_the_word function.
When you use readlines(), you get a list of lines. The random module has a handy method for picking a random element from such iterables which eliminates the need for "manually" dealing with indexing: random.choice(iterable).
All you need is this (no for loop necessary):
def generate_the_word(infile):
return random.choice(infile.readlines())
def main():
infile = open("words.txt","r")
generate_the_word(infile)
infile.close
main()
To avoid the costly operation of reading the file every time you want a single random word, you could also read the file in main and pass the list to generate_the_word instead:
import random
def generate_the_word(word_list):
return random.choice(word_list)
def main():
infile = open("words.txt","r")
lines = infile.readlines()
infile.close()
print generate_the_word(lines)
main()

Python, Adding all lines with a certain string from a file to list then randomly choosing which string to print?

import random
com=input("")
if com.startswith("/tip"):
numlines=sum(1 for line in open("C:\\Users\\Jace\\Desktop\\Python Programs\\Quote\\tip.txt"))-1
randomint=random.randint(0, numlines)
with open("C:\\Users\\Jace\\Desktop\\Python Programs\\Quote\\tip.txt", "r") as f:
i=1
for line in f:
if i==randomint:
break
i+=1
print(line.strip("\n"))
This is the part of the code for my random tips from a file so far. I wish to add another part of code where it adds all strings with any occurrence of the input placed after "/tip ", for example, if I were to type "/tip Hello", it would compile all lines in the text file with "Hello" in the string and do a random.choice() from the list, printing the one chosen. I don't really know where to start with this, any help would be appreciated. Thanks in advance!
You don't have to store all of the lines in a list. You can read the lines, selecting one at random and discarding the rest. This is called "resevoir sampling".
Your code might look like this:
import random
def random_line(iterator):
result = None
for n, item in enumerate(iterator):
if random.randint(0,n) == 0:
result = item
return result
# A random line
with open('tip.txt') as f:
print random_line(f) or "No tip for you!"
# A random line that has 'Hello'
with open('tip.txt') as f:
print random_line(line for line in f if 'Hello' in line) or "nothin!"
As a more special case, this code randomly chooses a matching line from the tips file, but falls back to a random non-matching line if no match exists. It has the advantages of reading the input file exactly once, and not having to store the entire tips file in memory.
import random
def random_line_with_fallback(iterator, match = lambda x: True):
result_match = None
result_all = None
n_match = n_all = 0
for item in iterator:
if match(item):
if random.randint(0, n_match) == 0:
result_match = item
n_match += 1
if random.randint(0, n_all) == 0:
result_all = item
n_all += 1
return (result_match or result_all).strip()
# A random line
with open('tip.txt') as f:
print random_line_with_fallback(f)
# Another way to do a random line. This depends upon
# the Python feature that "'' in line" will always be True.
com = ''
with open('tip.txt') as f:
print random_line_with_fallback(f, lambda line: com in line)
# A random line that has 'Hello', if possible
com = 'Hello'
with open('tip.txt') as f:
print random_line_with_fallback(f, lambda line: com in line)
References:
https://stackoverflow.com/a/23840292/8747
https://en.wikipedia.org/wiki/Reservoir_sampling
I think this is what you want, process each line of a text file, checking if the line has the word you're looking for. If so, add it to a list, and the randomly select one "line" for all possible "lines".
lines = []
with open("tip.txt", "r") as f:
for line in f:
if com in line:
lines.append(line)
print(random.choice(lines))

Trying to count words in a file using Python

I am attempting to count the number of 'difficult words' in a file, which requires me to count the number of letters in each word. For now, I am only trying to get single words, one at a time, from a file. I've written the following:
file = open('infile.txt', 'r+')
fileinput = file.read()
for line in fileinput:
for word in line.split():
print(word)
Output:
t
h
e
o
r
i
g
i
n
.
.
.
It seems to be printing one character at a time instead of one word at a time. I'd really like to know more about what is actually happening here. Any suggestions?
Use splitlines():
fopen = open('infile.txt', 'r+')
fileinput = fopen.read()
for line in fileinput.splitlines():
for word in line.split():
print(word)
fopen.close()
Without splitlines():
You can also use with statement to open the file. It closes the file automagically:
with open('infile.txt', 'r+') as fopen:
for line in fopen:
for word in line.split():
print(word)
A file supports the iteration protocol, which for bigger files is much better than reading the whole content in memory in one go
with open('infile.txt', 'r+') as f:
for line in f:
for word in line.split():
print(word)
Assuming you are going to define a filter function, you could do something along the line
def is_difficult(word):
return len(word)>5
with open('infile.txt', 'r+') as f:
words = (w for line in f for w in line.split() if is_difficult(w))
for w in words:
print(w)
which, with an input file of
ciao come va
oggi meglio di domani
ieri peggio di oggi
produces
meglio
domani
peggio
Your code is giving you single characters because you called .read() which store all the content as a single string so when you for line in fileinput you are iterating over the string char by char, there is no good reason to use read and splitlines you as can simple iterate over the file object, if you did want a list of lines you would call readlines.
If you want to group words by length use a dict using the length of the word as the key, you will want to also remove punctuation from the words which you can do with str.strip:
def words(n, fle):
from collections import defaultdict
d = defaultdict(list)
from string import punctuation
with open(fle) as f:
for line in f:
for word in line.split():
word = word.strip(punctuation)
_len = len(word)
if _len >= n:
d[_len].append(word)
return d
Your dict will contain all the words in the file grouped by length and all at least n characters long.

Is it possible to reverse the order of items in a list without using the built-in .reverse() function?

I have to write a program that will reverse the letters of the words in a file.
For example, if the file contains the words:
snow
tree
star
wreath
It would change them into:
wons
eert
rats
htaerw
Once that is done, I have to write a new file that will write them in reverse order so it would look like:
htaerw
rats
eert
wons
Here is my code:
def reverse(string):
#empty list for string
word = []
#for each letter in the string obtain the corresponding opposite number
#first letter to last letter, second letter to second last letter, etc...
for letter in range(len(string)-1, -1, -1):
word.append(string[letter])
#create main() function
def main():
#open file and read words in each line
input_file = open("words.txt", "r")
word_file = input_file.readlines()
#empty list for the words in the file, after their letters have been reversed
reversed_list = []
for word in range(len(word_file)):
reverse_word = reverse(word_file[word])
reversed_list.append(reverse_word)
#create new file of the reversed words IN REVERSED ORDER!
reverse_file = open("reverse.txt","w")
reverse_file.writelines(reversed_list)
reverse_file.close()
main()
How can I edit the main function to reverse the order of the words without using the built-in .reverse() function?
with open('path/to/input') as infile:
words = []
for line in infile:
words.append(line.strip()[::-1])
with open('path/to/output', 'w') as outfile:
for word in words[::-1]:
outfile.write(word)
outfile.write('\n')
One liners (since we all love them):
with open('path/to/input') as infile:
words = [line.strip()[::-1] for line in infile]
with open('path/to/output', 'w') as outfile:
outfile.write('\n'.join(words[::-1]))
reversey = lambda w: w if len(w) < 2 else reversey(w[1:]) + w[0]
>>> reversey("yellow")
reversex = labda x: x if len(x) < 2 else reversex(x[1:]) + [w[0]]
>>>reversex(["yellow","apple","purple","watermelon"])
is a recursive implementation ... but there are many ways to do this ... I wrote this function in a way that your teacher will know that you probably didnt write it... but hopefully you xcan look at what Im doing and change it into something you professor would expect from you
If you combine rev | tac (as in your case) then the result is a file in the reversed byte order (ignoring possible differences in whitespace). To get the desired output, you could read starting from the last byte and moving to the beginning of the file one byte at a time.
You could read/write all at once:
with open('words.txt', 'rb') as file, open('reverse.txt', 'wb') as outfile:
outfile.write(file.read()[::-1])
Or one byte at a time:
#!/usr/bin/env python
"""Print file in the reverse byte order."""
import os
with open('words.txt', 'rb') as file, open('reverse.txt', 'wb') as outfile:
file.seek(0, os.SEEK_END) # move to the end
for position in range(file.tell() - 1, -1, -1): # from last position
file.seek(position, os.SEEK_SET) # move back
outfile.write(file.read(1)) # read/write byte
The disadvantage is that reading one byte at a time is slow in Python. The advantage is that it also supports files that do not fit in memory.
mmap module allows to treat a file as a string:
#!/usr/bin/env python3
from mmap import ACCESS_READ, mmap
with open('words.txt') as f, mmap(f.fileno(), 0, access=ACCESS_READ) as s:
with open('reverse.txt', 'wb') as outfile:
for i in range(len(s) - 1, -1, -1):
outfile.write(s[i:i+1])
You could also read a block at time. See Most efficient way to search the last x lines of a file in python.

Categories

Resources