Python list index error (student files) - python

I am having problem with a list for an averaging program, it says:
'line 20, in
nameletter = (letter[int(num)])
IndexError: list index out of range'
This is the part of the code:
f2 = open("Classes" + "/Sorted/" + "Alphabetical.txt", "w")
letter = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
print(letter[num])
#Loop
while num <= 26:
nameletter = (letter[int(num)])
if os.path.exists("Classes" + "/" + nameletter + ".txt"):
#Opening the students file
f = open("Classes" + "/" + nameletter + ".txt")
List = f.read().splitlines()
f.close()
#Writing data to the file
f2.write(List[5] + " - score = " + List[6])
f2.write("\n")
else:
pass
num = int(num) + 1
f2.close()

Usually you are using a loop like
for one_letter in letter:
# your code
to access all items of a list.
Looping with the help of an index is OK as well, but you have to stop at the right point. In your case you have 26 item and since the index is 0-based, the highest number is 25 not 26.

Lists are indexed from 0. So the last index of your letters is 25 not 26.
But better use a for-loop, then you don't have to count by hand:
import string
f2 = open("Classes" + "/Sorted/" + "Alphabetical.txt", "w")
for lettername in string.uppercase:
try:
with open('Classes/%s.txt' % lettername) as inp:
lines = inp.read().splitlines()
except IOError:
pass
else:
f2.write('%s - score = %s' % (lines[5], lines[6]))
f2.close()

If you want to make it cleaner and succinct and do it like a ninja
wf = os.path.join("Classes", "Sorted", "Alphabetical.txt")
rf_ = os.path.join("Classes","{letter}.txt")
line = "{} - score = {}"
# separate the output strs from logic
alphabet = [chr(i) for i in range(65, 91)] # ['A', 'B', ..., 'Z']
with open(wf, "wt") as fw:
for letter in alphabet:
rf = rf_.format(letter=letter)
if os.path.exists(rf):
with open(rf) as fr:
ls = fr.read().splitlines()
print(line.format(ls[5], ls[6]), file=fw) # this will write to fw
Always use os.path.join instead of str acrobatics to be robust(Beazly). If the code didn't work please comment.

Related

What am I missing: list index out of range

import hashlib
import csv
import glob
def hash(text):
return hashlib.sha256(text.encode('UTF-8')).hexdigest()
def hash_file(input_file_name,output_file_name):
with open(input_file_name, newline='') as f_input, open(output_file_name, 'w', newline='') as f_output:
csv_input = csv.reader(f_input)
csv_output = csv.writer(f_output)
csv_output.writerow(next(csv_input)) # Copy the header row to the output
count = 0
print(count)
for customer_email in csv_input:
csv_output.writerow([hash(customer_email[0])])
count = count + 1
print(str(count) + " - " + customer_email[0])
f_input.close()
f_output.close
mylist = [f for f in glob.glob("*.csv")]
for file in mylist:
i_file_name = file
o_file_name = "hashed-" + file
hash_file(i_file_name,o_file_name)
I'm trying the above code and I keep getting a list index out of range. I have about 15 csv files that I would like to hash the email address on. It gets the first csv file and keeps iterating through it until I get the error message. Any help would be appreciated.
There was a blank line in my input that was causing the error
list index out of range mean that you try to acces a value of list by it's index, which is the length - 1 of the list value is not reach that index.
for example :
my_list = ['a', 'b']
lenght of my_list is 2. lenth - 1 = 1
mean that you only can acces the value of list until 1. like these:
my_list[0]
my_list[1]
if you try to access my_list[2], it will raise error list index out of range as your case.
to avoid the error you can:
index_to_access = 2
len(my_list) - index_to_access >= and my_list[index_to_access]
in your case maybe at here:
csv_output.writerow([hash(customer_email[0])])
count = count + 1
print(str(count) + " - " + customer_email[0])
change to :
customer_email = len(customer_email) - 1 >= 0 and customer_email[0] or ''
csv_output.writerow([hash(customer_email)])
count = count + 1
print(str(count) + " - " + customer_email)
actually there are many ways to handle that error.

Programming a sum function in python?

how to sum numbers attached to words in a text file(not separate them into digits) in python? (example: "a23 B55" - answer = 78)
thats what i did but its not quite right:
def rixum(file_name):
f = open(file_name,'r')
line = f.readline()
temp = line.split()
res = []
for word in temp:
i = 0
while i < len(word)-1:
if word[i].isdigit():
res.append(int(word[i:]))
print(sum(res))
f.close()
return sum(res)
This worked for me:
import re
string = 'F43 n90 i625'
def summ_numbers(string):
return sum([int(num) for num in re.findall('\d+', string)])
print(summ_numbers(string))
Output:
758
You don't really need to build a list - you can simply accumulate the values as you go along (line by line):
def rixum(filename):
with open(filename) as data:
for line in data:
total = 0
for token in line.split():
for i, c in enumerate(token):
if c.isdigit():
total += int(token[i:])
break
print(total)

How to sort a string list by a part of the 3rd string?

Beginner here:
I'm trying to sort a list of nicknames to the corresponding countries in the same line.
They come in this format:
FODORGBR + HU-Szombathely-2
ZSOLDPTE + HU-Debrecen-3
THAUSKTR + DE-Herzogenaurach-1
WRIGHNIL + UK-SuttonColdfield-2
KUROTADR + SK-KysuckeNoveMesto-1
KLERNMTT + DE-Herzogenaurach-1
BIRKNJHA + DE-Erlangen-111
CANECVAD + SK-KysuckeNoveMesto-1
MALDESND + DE-Herzogenaurach-1
I want to sort it by the country initials (so HU, DE etc.) with a caption.
So something like:
DE:
THAUSKTR
KLERNMTT
BIRKNJHA
MALDESND
HU:
FODORGBR
ZSOLDPTE
This is what I came up with do define the countries but I can't figure out how to sort all lines with it.
fw = open("NameList.txt")
for line_fw in fw:
if not line_fw.strip():
continue
cross = line_fw.find("+")
country = line_fw[cross+2:cross+4]
First split the list on " " and use operator.itemgetter to iterate over last element of list.
Or replace -1 in itemgetter by 3 if country code is always 3rd element in the list.
from operator import itemgetter
x = ["FODORGBR + HU-Szombathely-2","ZSOLDPTE + HU-Debrecen-3","THAUSKTR + DE-Herzogenaurach-1",
"WRIGHNIL + UK-SuttonColdfield-2","KUROTADR + SK-KysuckeNoveMesto-1","KLERNMTT + DE-Herzogenaurach-1",
"BIRKNJHA + DE-Erlangen-111","CANECVAD + SK-KysuckeNoveMesto-1","MALDESND + DE-Herzogenaurach-1"]
new_list = [i.split() for i in x]
new_list.sort(key=itemgetter(-1))
print([" ".join(i) for i in new_list])
Output:
['BIRKNJHA + DE-Erlangen-111', 'THAUSKTR + DE-Herzogenaurach-1', 'KLERNMTT + DE-Herzogenaurach-1', 'MALDESND + DE-Herzogenaurach-1', '
ZSOLDPTE + HU-Debrecen-3', 'FODORGBR + HU-Szombathely-2', 'KUROTADR + SK-KysuckeNoveMesto-1', 'CANECVAD + SK-KysuckeNoveMesto-1', 'WRI
GHNIL + UK-SuttonColdfield-2']
Using re.search and collections.defaultdict:
import re
from collections import defaultdict
d = defaultdict(list)
with open('NameList.txt') as fw:
for line in fw:
code = re.search(' (\w{2})-', line).group(1)
nick = re.search('(\w{8}) +', line).group(1)
d[code].append(nick)
Output:
defaultdict(list,
{'DE': ['THAUSKTR', 'KLERNMTT', 'BIRKNJHA', 'MALDESND'],
'HU': ['FODORGBR', 'ZSOLDPTE'],
'SK': ['KUROTADR', 'CANECVAD'],
'UK': ['WRIGHNIL']})
Your code for finding the country names looks just fine. One Piece of advice when working with files: use the with- statement instead of open and close. When using open, and an error occurs sometime before close is called, it's possible that the file is not properly closed, which can mess up all kinds of things. with closes the file no matter what happens inside the corresponding code block (It works similar to try - finally, see the above link for more info). So, like this:
with open('NameList.txt', 'r') as fw:
for line_fw in fw:
...
it is ensured that the file will always close down. By the way, instead of using line.find('+'), you can just use line.split('+'), which takes away the whole string slicing part.
Now, to your question: there are a few possibilities to use here. The simplest would be defining a list for every country, and appending the corresponding names to the right list:
de = []
hu = []
uk = []
sk = []
with open('NameList.txt', 'r') as fw:
for line_fw in fw:
if not line_fw.strip():
continue
country = line_fw.split('+')[1].split('-')[0].strip()
nickname = line_fw.split('+')[0]
if country == 'DE':
de.append(nickname)
elif country == 'HU':
hu.append(nickname)
elif country == 'UK':
uk.append(nickname)
else:
sk.append(nickname)
this will return a list for every country, containing the corresponding nicknames. As you see, however, this is very clunky and long. A more elegant solution is using a dictionary with the countries as keys and a list of the names as values:
d = {}
with open('NameList.txt', 'r') as fw:
for line_fw in fw:
if not line_fw.strip():
continue
country = line_fw.split('+')[1].split('-')[0].strip()
nickname = line_fw.split('+')[0].strip()
try:
d[country].append(nickname) # if country already exists in d, append the nickname
except KeyError:
d[country] = [nickname] # if country doesn't exist in d, make a new entry
which will create a dictionary looking like this (i just took the first few lines to illustrate it):
{'HU': ['FODORGBR', 'ZSOLDPTE'], 'DE': ['THAUSKTR'], 'UK': ['WRIGHNIL']}
Now, there are more elegant solutions for extracting the countries and nicknames, but some of those have been pointed out in other answers.
Finally, if i got that right, you want to write your results to a new file, or at least print them. Let's say you have a dictionary of the above form. Simply iterate over it's keys via for k in d:, add some newlines ('\n') inbetween and use join to convert the listsinto one string with newlines between all items:
for k in d:
print(k + ':\n' + '\n'.join(d[k]) + '\n')
which will print:
HU:
FODORGBR
ZSOLDPTE
DE:
THAUSKTR
UK:
WRIGHNIL
by adding with open(outputfile, 'w') as f: and replacing print with f.write, you can easily write this to a new file.
Here below is the Snippet which would help you :
sample = '''
FODORGBR + HU-Szombathely-2
ZSOLDPTE + HU-Debrecen-3
THAUSKTR + DE-Herzogenaurach-1
WRIGHNIL + UK-SuttonColdfield-2
KUROTADR + SK-KysuckeNoveMesto-1
KLERNMTT + DE-Herzogenaurach-1
BIRKNJHA + DE-Erlangen-111
CANECVAD + SK-KysuckeNoveMesto-1
MALDESND + DE-Herzogenaurach-1
'''
def find_between( s, first, last ):
try:
start = s.index( first ) + len( first )
end = s.index( last, start )
return s[start:end]
except ValueError:
return ""
data = sample.splitlines()
elements = {}
for indv in data:
code = find_between(indv,"+","-").strip()
value = find_between(indv,"","+").strip()
if code != '' and code in elements:
values = []
values.append(value)
values.extend(elements[code])
values = list(filter(None, values))
values.sort()
elements[code] = values
elif code != '':
values = []
values.append(value)
elements[code] = values
print(elements)
Output :
{'HU': ['FODORGBR', 'ZSOLDPTE'], 'DE': ['BIRKNJHA', 'KLERNMTT', 'MALDESND', 'THAUSKTR'], 'UK': ['WRIGHNIL'], 'SK': ['CANECVAD', 'KUROTADR']}

Python: How to replace each instance of an object with an ordered number?

The title may be a little cryptic so I'll elaborate on it here.
I've got a list of objects that are defined like so:
pname {
'amondo': 'amondo',
'android13': 'android13',
'android13s': 'android13s',
'android14': 'android14',
351 objects in total.
What I'm trying to do is replace the text in left-side quote with numbers starting from 1. So the end result would be something like:
'1': 'amondo',
'2': 'android13',
'3': 'android13s',
'4': 'android14',
all the way up until the last object.
I've created a python script with the following code:
import re
f = open('name.js', 'r')
inp = []
outp = []
for i in f:
inp.append(i)
for i in inp:
x = 1
while x < 352:
r = re.sub('.*\:', "'" + str(x) + "':", i)
x+=1
outp.append(r)
o = open('done.js', 'w')
for i in outp:
o.write(i)
f.close()
o.close()
But the output is:
'351': 'amondo',
'351': 'android13',
'351': 'android13s',
'351': 'android14',
I understand what I'm doing wrong and why the output is what it is but I'm not really sure how to fix it.
There's probably a function out there that could help me that I'm unaware of.
If you look carefully at your while loop, nothing is stopping it until x=352 and then you append r, this is not what you want... An easy way to count line is to use enumerate:
for x,i in enumerate(f):
r = re.sub('.*\:', "'" + str(x) + "':", i)
outp.append(r)
Try this:
with open('name.js') as infile, open('done.js', 'w') as outfile:
count = 0
for line in infile:
if ":" not in line:
outfile.write(line)
continue
count += 1
_, val = line.strip().split(":")
outfile.write("'{}' : {}\n".format(count, val))

I am trying to find and replace the values in the text file

I have a text file containing values (e.g.0.2803739 0.280314). I would like to replace the values in the text file in such a way that highest value will be replaced by lowest value and so on. e.g. If text file contains values from 1 to 10 then value 10 should be replaced by value 1, value 9 should be replaced by 2, value 8 should be replaced by 3 and so on. In the following script the 3rd "for loop" is getting ignored.
import fileinput
text_file = r"E:\Jagu\test123.txt"
f1 = open(text_file, 'r')
unique_v = set(f1.read().split())
a = list(unique_v)
new_list1= list(a)
new_list1.sort(reverse = True )
new_list2 = new_list1
new_list2.sort(reverse = False )
l = 0
m = len (new_list2)
m = m-1
f2 = open(text_file + ".tmp", 'w')
for j in new_list1:
c = new_list1 [l]
l = l + 1
for k in new_list2:
d = new_list2[m]
m = m - 1
for line in f1:
f2.write(line.replace(c,d))
print "replaced : " + str(c) + " with : " + str(d)
f1.close()
f2.close()
Hope the explanation is helpful to understand my issue. I am a beginner in Python programming. Any help would be appreciated.
Issue 1:
new_list2 = new_list1
This will make new_list2 and new_list1 point to same list. You need
new_list2 = list(a)
or
new_list2 = new_list[:]
Issue 2:
You cannot do
for line in f1:
after you have read() from f1.
Do
f1.seek(0)
l = f1.readlines()
for line in f1:
After you've called f1.read() you're at the end of the file, so call f1.seek(0) so you can read it again in the last for loop.
See Re-open files in Python? for more information.

Categories

Resources