how can i sort multiple dictionaries in one varible? - python

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.

Related

Sort value in txt file contain {string, number} using Python

I have a .txt file as per below:
testa, 10
testb, 50
testc, 20
I want to sort it reversely, based on the number each line located on the right side of comma, become the result like below:
testb, 50
testc, 20
testa, 10
I have tried to append each line to a list and use sort(), but fail.
Any way to do that in Python? Take note my file is txt.
This prints the lines in reverse order
with open('test.txt') as f:
lines = f.readlines()
with open('out.txt', 'w') as f:
for line in sorted(lines, key=lambda x: x.split()[1], reverse=True):
f.write(line.strip() + '\n')
Edited to write the out.txt file
You can specify a key=func argument to the sorted() built-in function, which specify a value to be used as comparing value between items. The code to do it would be:
lines = open('input.txt').read().splitlines()
splitted = (line.split(', ') for line in lines)
items = ((i[0], int(i[1])) for i in splitted)
# Reversed sort
reversed_items = sorted(items, key=lambda i: -i[1])
open('output.txt', 'w+').write('\n'.join((f"{i[0]}, {i[1]}" for i in reversed_items)))
Documentation: https://docs.python.org/3/howto/sorting.html#key-functions

Read lines 2by 2 python

I want to read all lines from a file and store in a list, 2 by 2 elements until list finish iterating.
-Read first 2 lines from a list, and do stuff
-Continue reading more 2 lines, and do stuff
-Do so until whole list finish
Inside test.txt
aa
bb
cc
dd
ee
ff
gg
hh
accounts_list = []
with open('test.txt', 'r') as f:
accounts_list = [line.strip() for line in f]
for acc in accounts_list:
#do stuff with 2
#continue reading more 2
# do another stuff with the next 2
# read until whole list finish
How i can do that, i can't make it.
I think iterating through the indices by 2 steps range(0, len(accounts_list), 2) instead of list item of accounts_list should work
accounts_list = []
with open('test.txt', 'r') as f:
accounts_list = [line.strip() for line in f]
for i in range(0, len(accounts_list), 2):
acc1 = accounts_list[i]
acc2 = accounts_list[i + 1]
#do stuff with 2
#continue reading more 2
# do another stuff with the next 2
# read until whole list finish
If you use an explicit iterator (instead of letting the for loop create its own), you can read two lines per iteration: one by the loop itself, the second in the body.
with open('test.txt', 'r') as f:
itr = iter(f)
for acc1 in itr:
acc2 = next(itr)
# Do stuff with acc1 and acc2
# If the file has an odd number of lines,
# you should wrap the assignment to acc2
# in a try statement to catch the explicit StopIteration it will raise
I don't really like the asymmetry of reading the two lines in two different ways, so I would use an explicit while loop and use next to get both lines.
with open('test.txt', 'r') as f:
itr = iter(f)
while True:
try:
acc1 = next(itr)
acc2 = next(itr)
except StopIteration:
break
# Do stuff with acc1 and acc2
Also, be sure to check the recipe section of the itertools documentation for the grouper recipe.
To store file in a nested list "2 by 2 elements":
code:
with open('test.txt', 'r') as f:
accounts_list = [[acc0.strip(), acc1.strip()] for acc0, acc1 in zip(f, f)]
output:
[['aa', 'bb'], ['cc', 'dd'], ['ee', 'ff'], ['gg', 'hh']]
then you can iterate over on this list to work with
Here's one reasonably idiomatic way of doing it. The key is the use of zip(it, it) (passing the same iterator twice), which causes zip to create a generator of tuples consisting of pairs of values from it. (A more general form of this idiom is documented under "tips and tricks" in the Python documentation for zip):
with open('test.txt', 'r') as f:
accounts_iter = (line.strip() for line in f)
for first, second in zip(accounts_iter, accounts_iter):
# Just an example
print(f" First is '{first}'")
print(f"Second is '{second}'")
That snippet does not create a list; it simply iterates over the input. Unless you need to keep the data for later use, there is no point in creating the list; it's simply a waste of memory (which could be a lot of memory if the file is large.) However, if you really wanted a list, for some reason, you could do the following:
with open('test.txt', 'r') as f:
accounts_iter = (line.strip() for line in f)
accounts = [*zip(accounts_iter, accounts_iter)]
That will create a list of tuples, each tuple containing two consecutive lines.
Two other notes:
This only works with iterators (which includes generators); not with iterable containers. You need to turn an iterable container into an iterator using the iter built-in function (as is done in the example in the Python docs).
zip stops when the shortest iterator finishes. So if your file has an odd number of lines, the above will ignore the last line. If you would prefer to see an error if that happens, you can use the strict=True keyword argument to zip (again, as shown in the documentation). If, on the other hand, you'd prefer to have the loop run anyway, even with some missing lines, you could use itertools.zip_longest instead of zip.

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)

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

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.

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