-3

I have a dictionary, which is written in .txt file in this way(picture)enter image description here

How can I input it in my programm?

Thanks!

Tried a normal way of inputting from a file but obviously it didnt work. json doesnt work with sets :c

  • [*Please do not post text as images*](https://meta.stackoverflow.com/q/285551). Copy and paste the text into your question and use the code formatting tool (`{}` button) to format it correctly. Images are not searchable, cannot be interpreted by screen readers for those with visual impairments, and cannot be copied for testing and debugging purposes. Use the [edit] link to modify your question. – MattDMo Dec 16 '22 at 01:09
  • 6
    There is no dictionary in the file. – blhsing Dec 16 '22 at 01:09
  • Where is the text file coming from? – MattDMo Dec 16 '22 at 01:10
  • 1
    this txt file has no aparent dictionary in it. does each line represent a dictionary with an int key and a dict value? – Davi A. Sampaio Dec 16 '22 at 02:42

1 Answers1

1

I've retyped the contents of your file, let's load it first:

with open("weird_dictionary.txt", 'r') as f:
    weird_dict = f.read()
print(weird_dict)
Output:
0, {1, 2}
1, {0, 3, 4}
2, {0}
3, {1}
4, {2, 3}

No way this is a dictionary. Not in this universe at least.
We can assume that the first digit in each line is a key and keeping in mind your:

json doesnt work with sets

We may assume that contents within curly braces are sets.
Okay.

Eval

One way to cast this mess into a dictionary with sets is to use eval().
But we'll need to prepare this string to something that can be evaluated without an error. I'll use for this.

import re
s = '{' + re.sub(r'(?<=\d),(?=\s{)', ':', weird_dict) + '}'
s = re.sub(r'\n', ', ', s)
print(s)
Output:
{0: {1, 2}, 1: {0, 3, 4}, 2: {0}, 3: {1}, 4: {2, 3}}

Now this is a valid dictionary with sets.

  • first I change , to : to have a valid dictionary syntax
    • (?<=\d) is a positive lookbehind
      not really necessary here but in case your file is messed up even more, it's worth having
    • (?=\s{) is a positive lookahead
      we make sure comma comes before space and opening curly brace
  • curly braces are added to the beginning and end of the string
  • \n new line is substituted to comma and space

Now you may do eval(s) but a safer option would be to use literal_eval:

from ast import literal_eval
e = literal_eval(s)
print(e)
print(type(e))
print(type(e[1]))
Output:
{0: {1, 2}, 1: {0, 3, 4}, 2: {0}, 3: {1}, 4: {2, 3}}
<class 'dict'>
<class 'set'>

Yaml

Generally as a rule of thumb you should remember, never use eval in any it's implementation when there are other options to parse.

And there is one, works fine with sets. Json does not, you are right.

Look at yaml syntax for sets, we'll once again have to adopt your mess to yaml format, this time it will require some parsing and this can be done without regex using python syntax alone:

s = ''
for i in weird_dict.split('\n'):
    s += i[:i.find('{')].replace(',',':') + '!!set\n'
    for j in i[i.find('{')+1:-1].split(', '):
        s += '  ? {}\n'.format(j)
print(s)

Or one liner:

s = '\n'.join([i[:i.find('{')-1]+' !!set\n'+'\n'.join(['  ? '+j for j in i[i.find('{')+1:-1].split(', ')]) for i in weird_dict.split('\n')]).replace(',',':')
print(s)
Output:
0: !!set
  ? 1
  ? 2
1: !!set
  ? 0
  ? 3
  ? 4
2: !!set
  ? 0
3: !!set
  ? 1
4: !!set
  ? 2
  ? 3

Now this is an absolutely valid syntax for yaml, and yaml is much safer to cast string to data structures compared to eval():

import yaml
e = yaml.safe_load(s)
print(e)
print(type(e))
print(type(e[1]))
Output:
{0: {1, 2}, 1: {0, 3, 4}, 2: {0}, 3: {1}, 4: {2, 3}}
<class 'dict'>
<class 'set'>

Manual parse

As a final option you may just parse the contents straight into dict:

my_dict = {}
for i in weird_dict.split('\n'):
    my_dict[int(i[0])] = set([int(j) for j in i[i.find('{')+1:-1].split(', ')])
print(my_dict)

Or one liner:

my_dict = {int(i[0]): set([int(j) for j in i[i.find('{')+1:-1].split(', ')]) for i in weird_dict.split('\n')}
print(my_dict)
Output:
{0: {1, 2}, 1: {0, 3, 4}, 2: {0}, 3: {1}, 4: {2, 3}}
DiMithras
  • 605
  • 6
  • 14