0

I have a text file with contents such as:

{'InventoryTake':'Key','OtherSceneNode':'Shed','AddOtherScene':'ShedOpen'}

And the code that retrieves the data from the text file:

    readin = eventVar.readline()
    Results = eval(readin)

The problem I'm having is that I need to keep my dictionary in order due to the nature of the code it runs. However python stores dictionary keys in random order.

I have tried using an ordered Dictionary to preserve the order, but this doesn't make a difference. I think this is because by the time the ordered dictionary gets a hold of the information, it has already been sorted by whatever is reading it in from the file.

I have tried eval, literal_eval and a json parser to read the data in correctly, but the dictionary always comes out in the wrong order when running the program.

The aim of this part of the program is to allow the text file dictionary to store as many of those pairs as possible (OtherSceneNode and AddOtherScene / TakeOtherScene). So I can't assume there is only one set of those key value pairs.

I'm using python 2.7.5, and if it helps the order its coming out in is:

{'InventoryTake':'Key','AddOtherScene':'ShedOpen','OtherSceneNode':'Shed'}

I could redo the text files to take specific lines, but that will make my text files even more complicated and I feel its just avoiding a problem rather than solving one.

user3161729
  • 303
  • 2
  • 15
  • Why does the order matter in your case? If the Order really matters, you can convert the dictionary to a list and write the list to the file. – thefourtheye Jan 05 '14 at 02:56
  • there is no order in a dict in python. Use OrderedDict to preserve insertion order. – njzk2 Jan 05 '14 at 02:58
  • Why do you want them in a dictionary (other than to be able to parse easily using eval)? That's not an appropriate container if you want to support duplicate keys. – jarmod Jan 05 '14 at 02:59
  • It's kind of a text adventure game base. This is from an event text file which handles events. The dictionary is the list of changes made by the event such as updating inventory. The reason it needs to be in order is because I want to control the order the changes happen in. – user3161729 Jan 05 '14 at 03:02
  • possible duplicate http://stackoverflow.com/questions/16641110/converting-string-to-ordered-dictionary – Guy Gavriely Jan 05 '14 at 03:25

3 Answers3

1

One method would be to look up the parsed data pairs in the string to find their original relative order:

line = "{'InventoryTake':'Key','OtherSceneNode':'Shed','AddOtherScene':'ShedOpen'}"
data = eval(line)
sorted(data.items(), key=lambda pair: line.index("'%s','%s'" % pair)

which gives me:

[('InventoryTake', 'Key'),
('OtherSceneNode', 'Shed'),
('AddOtherScene', 'ShedOpen')]
glenn mcdonald
  • 15,290
  • 3
  • 35
  • 40
1

This should do the trick, and is shorter than most of the other solutions.

from collections import OrderedDict

data = []
for line in eventVar.readline():
    # Remove braces
    line = line.strip()[1:-1]
    results = OrderedDict()
    # Split by comma sign
    for pair in line.split(','):
        # Get key and value by splitting on colon
        key, value = pair.split(':')
        # Use eval to get rid of quotation surrounding the key and value
        results[eval(key)] = eval(value)
        # Add the results from reading this line to a list
        data.append(results)
Steinar Lima
  • 7,644
  • 2
  • 39
  • 40
0

This got a bit wordy, but it appears to do what you're asking for:

#!/usr/local/cpython-3.3/bin/python

import shlex
import collections

def strip_single_quote(string):
    assert string[0] == "'"
    assert string[-1] == "'"
    return string[1:-1]

def dict_to_tuples(string):
    list_ = list(shlex.shlex(string))
    assert list_[0] == '{'
    assert list_[-1] == '}'
    list_ = list_[1:-1]
    print(list_)
    len_list = len(list_)

    for base_index in range(0, len_list, 4):
        assert list_[base_index + 1] == ':'
        if list_[base_index + 3:]:
            assert list_[base_index + 3] == ','
        key = strip_single_quote(list_[base_index + 0])
        value = strip_single_quote(list_[base_index + 2])
        yield (key, value)

def main():
    string = "{'InventoryTake':'Key','OtherSceneNode':'Shed','AddOtherScene':'ShedOpen'}"
    od = collections.OrderedDict(dict_to_tuples(string))
    print(od)
dstromberg
  • 6,954
  • 1
  • 26
  • 27