H. eyXD
H. eyXD

Reputation: 45

Read & split file into dictionary

I have a file in which my data is like:

1 [0,1, 4, 89]     
2 [3, 56, 6]     
3 [3,4,0]

And so on.

I'd like to read this file to access data line by line in my script so I try this to read my file and memorize it in a dictionary:

dictionary = {}

with open('file.txt') as f:
    for line in f:
        nb, list = line.split(' ')
        dictionary[nb] = list 

Then I will do something like:

for e in dictionary:
    etc.

I have this error:

too many values to unpack

because I don't know how to deal with the second split element which is a list.

Is there an other way to access and work with any input file easily?

Upvotes: 1

Views: 3914

Answers (4)

TigerhawkT3
TigerhawkT3

Reputation: 49318

Use the maxsplit argument and ast.literal_eval():

import ast
dictionary = {}

with open('file.txt') as f:
    for line in f:
        nb, l = line.split(maxsplit=1)
        dictionary[nb] = ast.literal_eval(l)

Note that I've changed the name of the list to something that doesn't mask the built-in function list(), and used the default delimiter of any whitespace.

Upvotes: 1

Pynchia
Pynchia

Reputation: 11590

Would this do?

import ast
d = dict()
with open('file.txt') as f:
    for line in f:
        k, l = line.split(' ', 1)
        d[k] = ast.literal_eval(l)

print(d)

it produces

{'3': [3, 4, 0], '1': [0, 1, 4, 89], '2': [3, 56, 6]}

In case you want the key to be an integer instead of a string just do

d[int(k)] = ast.literal_eval(l)

Upvotes: 1

Remi Guan
Remi Guan

Reputation: 22282

First at all, you can set a maxsplit argument of str.split(). From the document:

str.split(sep=None, maxsplit=-1)

Return a list of the words in the string, using sep as the delimiter string. If maxsplit is given, at most maxsplit splits are done (thus, the list will have at most maxsplit+1 elements). If maxsplit is not specified or -1, then there is no limit on the number of splits (all possible splits are made).

Demo:

>>> s = '1 [0,1, 4, 89]'
>>> s.split(' ', 1)
['1', '[0,1, 4, 89]']
>>> s.split(' ')
['1', '[0,1,', '4,', '89]']

>>> s.split(' ')[1]
'[0,1,'
>>> s.split(' ', 1)[1]
'[0,1, 4, 89]'

Then you need convert the string of list to a real list. I'd recommend use ast.literal_eval(). From the document:

ast.literal_eval(node_or_string)

Safely evaluate an expression node or a string containing a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None.

For example:

>>> import ast
>>> s = '1 [0,1, 4, 89]'
>>> s.split(' ', 1)[1]
'[0,1, 4, 89]'
>>> ast.literal_eval(s.split(' ', 1)[1])
[0, 1, 4, 89]
>>> type(ast.literal_eval(s.split(' ', 1)[1]))
<class 'list'>
>>> type(s.split(' ', 1)[1])
<class 'str'>

If you need remove the \n after the string, just use str.strip(). From the document:

str.strip([chars])

Return a copy of the string with the leading and trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace.

Use it like this:

>>> '   1 [0,1, 4, 89]   '.strip()
'1 [0,1, 4, 89]'
>>> '1 [0,1, 4, 89]\n'.strip()
'1 [0,1, 4, 89]'
>>> 

It remove all tabs, newlines, spaces before and after the string, If you just want remove the spaces, newlines before or after the string, take a look at str.lstrip() and str.rstrip().


So you can write your code like this:

import ast
dictionary = {}

with open('file.txt') as f:
    for line in f:
        key, value = line.strip().split(1)
        dictionary[key] = value

If you want the dictionary's keys be int objects, just use int() function to convert it like:

import ast
dictionary = {}

with open('file.txt') as f:
    for line in f:
        key, value = line.strip().split(' ', 1)
        dictionary[int(key)] = value

Upvotes: 3

Mike M&#252;ller
Mike M&#252;ller

Reputation: 85442

For a save eval use ast.literal_eval:

from ast import literal_eval

data = {}
with open('file.txt') as fobj:
    for line in fobj:
        key, rest = line.split(None, 1)
        data[key] = literal_eval(rest)


>>> data
{'1': [0, 1, 4, 89], '2': [3, 56, 6], '3': [3, 4, 0]}

From the docs:

ast.literal_eval(node_or_string)

This can be used for safely evaluating strings containing Python values from untrusted sources without the need to parse the values oneself.

Upvotes: 1

Related Questions