Python file i/o looping, why doesn't dictionary get updated? - python

I am trying to create a function that opens a file for reading, skips the first line because it is the header, gets every line and splits at ':' to get keys and values to put into a dictionary and then return that dictionary. My problem is that my function is just giving me an empty dictionary. How do I fix this?
ex from line 2: 'Bulbasaur': (1, 'Grass', 'Poison', 1, False)
'Bulbasaur' is the key and everything after colon is the value for that key.
So I need to return: my_dict={'bulbasaur':(1, 'Grass', 'Poison', 1, False)}
Here is my function:
def read_info_file(filename):
f=open(filename, 'r') #open file for reading
lines=f.readlines()[1:] #skip first line
d={} #create dictionary
for lines in f: #iterate for all lines
x=lines.split(':') #split at colon
a=x[0] #map keys to values
b=x[1]
d[a]=b #add to dictionary
return d #return dictionary

f = open(filename, 'r') gives your an iterator over the lines of the file.
After you do lines = f.readlines()[1:] the iterator has yielded all its values because the invocation of readlines calls __next__ on f until there are no lines left.
Now here's the problem: After you have done all that, you issue for lines in f i.e. you try to loop over the iterator again. But since it is empty, the body of your for loop will never be executed.
There are several ways to fix your code. The most straight forward is to loop over your list lines, not f, i.e. something like for line in lines.
On the other hand, it does not seem like you need a full fledged list of all the lines prior to iteration, so consider just looping over f directly without calling readlines beforehand.

Change it to:
lines=f.readlines()[1:] #skip first line
d={} #create dictionary
for line in lines: #iterate for all lines
if ':' in line:
x=line.strip().split(':') #split at colon
a=x[0] #map keys to values
b=x[1]
d[a]=b #add to dictionary
return d #return dictionary
...
Otherwise if no colon in the line, you will get IndexError.

Related

How do I sort a text file after the last instance of a character?

Goal: Sort the text file alphabetically based on the characters that appear AFTER the final slash. Note that there are random numbers right before the final slash.
Contents of the text file:
https://www.website.com/1939332/delta.html
https://www.website.com/2237243/alpha.html
https://www.website.com/1242174/zeta.html
https://www.website.com/1839352/charlie.html
Desired output:
https://www.website.com/2237243/alpha.html
https://www.website.com/1839352/charlie.html
https://www.website.com/1939332/delta.html
https://www.website.com/1242174/zeta.html
Code Attempt:
i = 0
for line in open("test.txt").readlines(): #reading text file
List = line.rsplit('/', 1) #splits by final slash and gives me 4 lists
dct = {list[i]:list[i+1]} #tried to use a dictionary
sorted_dict=sorted(dct.items()) #sort the dictionary
textfile = open("test.txt", "w")
for element in sorted_dict:
textfile.write(element + "\n")
textfile.close()
Code does not work.
I would pass a different key function to the sorted function. For example:
with open('test.txt', 'r') as f:
lines = f.readlines()
lines = sorted(lines, key=lambda line: line.split('/')[-1])
with open('test.txt', 'w') as f:
f.writelines(lines)
See here for a more detailed explanation of key functions.
Before you run this, I am assuming you have a newline at the end of your test.txt. This will fix "combining the second and third lines".
If you really want to use a dictionary:
dct = {}
i=0
with open("test.txt") as textfile:
for line in textfile.readlines():
mylist = line.rsplit('/',1)
dct[mylist[i]] = mylist[i+1]
sorted_dict=sorted(dct.items(), key=lambda item: item[1])
with open("test.txt", "w") as textfile:
for element in sorted_dict:
textfile.write(element[i] + '/' +element[i+1])
What you did wrong
In the first line, you name your variable List, and in the second you access it using list.
List = line.rsplit('/', 1)
dct = {list[i]:list[i+1]}
Variable names are case sensitive so you need use the same capitalisation each time. Furthermore, Python already has a built-in list class. It can be overridden, but I would not recommend naming your variables list, dict, etc.
( list[i] will actually just generate a types.GenericAlias object, which is a type hint, something completely different from a list, and not what you want at all.)
You also wrote
dct = {list[i]:list[i+1]}
which repeatedly creates a new dictionary in each loop iteration, overwriting whatever was stored in dct previously. You should instead create an empty dictionary before the loop, and assign values to its keys every time you want to update it, as I have done.
You're calling sort in each iteration in the loop; you should only call once it after the loop is done. After all, you only want to sort your dictionary once.
You also open the file twice, and although you close it at the end, I would suggest using a context manager and the with statement as I have done, so that file closing is automatically handled.
My code
sorted(dct.items(), key=lambda item: item[1])
means that the sorted() function uses the second element in the item tuple (the dictionary item) as the 'metric' by which to sort.
`textfile.write(element[i] + '/' +element[i+1])`
is necessary, since, when you did rsplit('/',1), you removed the /s in your data; you need to add them back and reconstruct the string from the element tuple before you write it.
You don't need + \n in textfile.write since readlines() preserves the \n. That's why you should end text files with a newline: so that you don't have to treat the last line differently.
def sortFiles(item):
return item.split("/")[-1]
FILENAME = "test.txt"
contents = [line for line in open(FILENAME, "r").readlines() if line.strip()]
contents.sort(key=sortFiles)
with open(FILENAME, "w") as outfile:
outfile.writelines(contents)

Random.Choice() is returning entire string

I am trying to write a program that queries a word document and returns a line randomly from that document. Currently, every line from the document is being returned, even when I apply random.choice(). Any thoughts on how I can correct this?
I ran a len() on my list and confirmed it is returning multiple variables, but the entire list is still being returned.
import random
filename = 'happy document.txt'
dictionary_list = []
with open(filename) as file_object:
lines = file_object.readlines()
for l in lines:
lines = [l.strip('\n') for l in lines]
dictionary_list.append(lines)
random_choice = random.choice(dictionary_list)
print(random_choice)
You append the whole list of lines to your dictionary_list on each loop, so whichever of its items you choose, it's the whole list...
You can do:
import random
filename = 'happy document.txt'
with open(filename) as file_object:
lines = [line.strip('\n') for line in file_object]
random_choice = random.choice(lines)
print(random_choice)
As a side note, for line in file_object iterates on the lines of the file, you don't need to use readlines first and iterate again on the list of lines.
You want
dictionary_list.extend(lines)
to "un-nest" the lines into your dictionary_list.

importing from a text file to a dictionary

filename:dictionary.txt
YAHOO:YHOO
GOOGLE INC:GOOG
Harley-Davidson:HOG
Yamana Gold:AUY
Sotheby’s:BID
inBev:BUD
code:
infile = open('dictionary.txt', 'r')
content= infile.readlines()
infile.close()
counters ={}
for line in content:
counters.append(content)
print(counters)
i am trying to import contents of the file.txt to the dictionary. I have searched through stack overflow but please an answer in a simple way (not with open...)
First off, instead of opening and closing the files explicitly you can use with statement for opening the files which, closes the file automatically at the end of the block.
Secondly, as the file objects are iterator-like objects (one shot iterable) you can loop over the lines and split them with : character. You can do all of these things as a generator expression within dict function:
with open('dictionary.txt') as infile:
my_dict = dict(line.strip().split(':') for line in infile)
I assume that you don't have semi-colons in your keys.
In that case you should:
#read lines from your file
lines = open('dictionary.txt').read().split('\n')
#create an empty dictionary
dict = {}
#split every lines at ':' and use the left element as a key for the right value
for l in lines:
content = l.split(':')
dict[content[0]] = content[1]

how can i sort multiple dictionaries in one varible?

there are several dictionaries in the variable highscores. I need to sort it by its key values, and sorted() isn't working.
global highscores
f = open('RPS.txt', 'r')
highscores = [line.strip() for line in f]
sorted(highscores)
highscores = reverse=True[:5]
for line in f:
x = line.strip()
print(x)
f.close()
this is the error:
TypeError: 'bool' object is not subscriptable
sorted(v) an iterator that returns each element of v in order; it is not a list. You can use the iterator in a for loop to process the elements one at a time:
for k in sorted(elements): ...
You can transform each element and store the result in a list:
v = [f(k) for k in sorted(elements)]
Or you can just capture all elements into a list.
v = list(k)
Note that in the code above, elements are strings from a file, not a dictionary.
The following should do what (I think) you want:
with open('RPS.txt', 'r') as f: # will automatically close f
highscores = [line.strip() for line in f]
highscores = sorted(highscores, reverse=True)[:5]
for line in highscores:
print(line)
The primary problem was the way you're using sorted(). And, at the end, rather than trying to iterate though the lines of the file again (which won't work because files aren't list and can't be arbitrarily iterated-over) WHat the code above does is sort the lines read from the file and then takes first 5 of that list, which was saved in highscores. Following that it prints them. There's no need to strip the lines again, that was taken care of when the file was first read.

python parse prints only first line from list

I have a list 'a',where I need to print all the matching letters of the list with the line of a text file 'hello.txt'.But it only prints the first word from the list and line instead of all the list and lines
a=['comp','graphics','card','part']
with open('hello.txt', 'r') as f:
for key in a:
for line in f:
if key in line:
print line, key
It results as:
comp and python
comp
Desired output:
comp and python
comp
graphics and pixel
graphics
micro sd card
card
python part
part
Please help me to get desires output.Answers willbe appreciated!
The file-object f is an iterator. Once you've iterated it, it's exhausted, thus your for line in f: loop will only work for the first key. Store the lines in a list, then it should work.
a=['comp','graphics','card','part']
with open('hello.txt', 'r') as f:
lines = f.readlines() # loop the file once and store contents in list
for key in a:
for line in lines:
if key in line:
print line, key
Alternatively, you could also swap the loops, so you iterate the file only once. This could be better if the file is really big, as you won't have to load all it's contents into memory at once. Of course, this way your output could be slights different (in a different order).
a=['comp','graphics','card','part']
with open('hello.txt', 'r') as f:
for line in f: # now the file is only done once...
for key in a: # ... and the key loop is done multiple times
if key in line:
print line, key
Or, as suggested by Lukas in the comments, use your original loop and 'reset' the file-iterator by calling f.seek(0) in each iteration of the outer key loop.

Categories