-1
name,score #an example
a,1,
s,2,
d,3,
f,4,
g,5,
h,6,
j,7,
k,8,
l,9,
q,10,

This is my file. I want to make this into a dictionary (a:1,s:2...)

number_of_lines = len(open("scores.txt").readlines(  ))
d = {}
with open("scores.txt") as f:
   for line in range(number_of_lines-1):   #-1 removes the last line which is only \n
     (key, value) = line.split(",")
     d[key] = value
print(d)

I keep getting the error AttributeError: 'int' object has no attribute 'split' don't know why.

Can you debug this?

Thank in advance,

Daniel
  • 63
  • 5
  • 1
    `range(number_of_lines-1)` will give you ints from 0 to number_of_lines -1, so line will be an int and on each loop will increse. so, `0, 1, 2, 3` etc, so you cant split an int. Do you mean to do `(key, value) = f.readline().split(",")` but i dont see why you care about the length of the file – Chris Doyle Jun 08 '20 at 10:19
  • @ChrisDoyle Thanks for responding. Then length is an issue because then I get the error expecting only 2, because there is another line at the end of the file with only \n – Daniel Jun 08 '20 at 10:34
  • @Daniel That has to do with your logic in looping over the lines. You can safely do `if len(line.strip()) == 0: continue` assuming you actually put the line itself in the variable `line`. See my code below, third example. Should explain this in more detail. – Torxed Jun 08 '20 at 10:37

3 Answers3

4

range() returns numbers, not the actual lines. Since you store the output of range into lines you won't be able to do line.split() as lineis not the actual line, but the value from range(). Instead, do something like this:

d = {}
with open("scores.txt") as f:
    for line in f:
        key, value = line.split(",")
        d[key] = value
print(d)

If you need the index of the line you're on (which you never used, so I don't know if you do), you can use the enumerate function.

d = {}
with open("scores.txt") as f:
    for index, line in enumerate(f.readlines()):
        key, value = line.split(",")
        d[key] = value
print(d)

Mentioned in the comments, there's issues with length of the file etc. But that can be safely checked in the for loop:

d = {}
with open("scores.txt") as f:
    for index, line in enumerate(f.readlines()):
        if len(line.strip()) <= 0: continue
        elif index == 0: continue # Skip the header or use the CSV lib
        key, value = line.split(",")
        d[key] = value
print(d)

To better understand this, you can lab with the range function (if you don't like to read the docs) on a more standalone basis by doing:

for line in range(0, 10):
    print(type(line), line)

Hopefully this solves your issue but also teaches what the range function does.

Lastly, consider using the csv module:

import csv
with open('scores.txt') as csvfile:
    reader = csv.DictReader(csvfile, delimiter=',')
    for row in reader:
        print(row['name'], row['score'])

Pro's: handles empty lines, sorts everything in to a dictionary for you, skips the headers (or more accurately, puts them in as the key in the dict per row) and lastly, handles a lot of CSV "magic" for you (like special delimiters, quote chars etc)

You can use the csv lib to inline create the final result that you're after altho it's a bit slow, you'd probably better off reading and working with the data line by line unless it's for database purposes like this:

import csv
with open('scores.txt') as csvfile:
    reader = csv.DictReader(csvfile, delimiter=',')
    d = {row['name']:row['score'] for row in reader}
Torxed
  • 22,866
  • 14
  • 82
  • 131
  • Thanks for responding. The first example get the error ValueError: too many values to unpack (expected 2) which is why I chose range, I will look at the others – Daniel Jun 08 '20 at 10:37
  • @Daniel Check the third example, as it explains that particular issue. It has to do with the fact that you're not checking if the line is empty or not. I also added a "skip the first (0) line" as it's a CSV header item and you probably don't want that in your dict. But ultimately, just use the `csv` library, it takes care of these things for you. – Torxed Jun 08 '20 at 10:38
  • I get the same for the second one – Daniel Jun 08 '20 at 10:40
  • The last one gives TypeError: 'delimiter' is an invalid keyword argument for open() – Daniel Jun 08 '20 at 10:40
  • @Daniel Yepp, sorry, meant to put that on the `csv.reader` object as it's a csv property not a file property. Fixed the type-o. That's what you get for being to fast when writing it off : ) But the example is taken from the documentation so the correct information was there all along :) – Torxed Jun 08 '20 at 10:46
  • @Daniel glad it was of use. I added a bonus slightly stolen inspiration from [here](https://stackoverflow.com/questions/6740918/creating-a-dictionary-from-a-csv-file) as I didn't find it until I was writing this comment. But that would give you your final result I hope. – Torxed Jun 08 '20 at 10:54
  • 1
    It's good to learn the essence of range and all of its uses and qualities – Daniel Jun 08 '20 at 11:02
1

you can use pandas for this

import pandas as pd
d = pd.read_csv('scores.txt').set_index('name')['score'].to_dict()

This works well with comma separated files, and is faster

Yati Raj
  • 456
  • 2
  • 6
  • 10
1

You could use a dict comprehension:

data = """
a,1,
s,2,
d,3,
f,4,
g,5,
h,6,
j,7,
k,8,
l,9,
q,10,
"""

dct = {key: value for line in data.split("\n") if line for key, value, *_ in [line.split(",")]}
print(dct)
# {'a': '1', 's': '2', 'd': '3', 'f': '4', 'g': '5', 'h': '6', 'j': '7', 'k': '8', 'l': '9', 'q': '10'}


Or - with your file (considering the header, that is):
with open("scores.txt") as f:
    data = f.read()
    dct = {key: value 
           for line in data.split("\n")[1:] if line 
           for key, value, *_ in [line.split(",")]}
Jan
  • 42,290
  • 8
  • 54
  • 79
  • 1
    Friendly reminder to the OP, don't miss the detail that Jan ignored `name,score #an example` at the start of your file - aka, don't forget to manipulate the data into the above example. – Torxed Jun 08 '20 at 10:35
  • @Torxed: Thanks for spotting that out. I updated the `file` section. – Jan Jun 08 '20 at 10:36