-1

I am new in Python.

I am trying to create many ordereddict,but because I am filling it out in messed sequence I had to create a function to pass in the normal dict to get the order I want.

info = dict()
info['age'] = 3
...

keys=['id','name','age','ck_id','image']
def fix_order(my_dict):
    new_queue = OrderedDict()
    for k in keys:
        new_queue[k] = item[k]
    return new_queue

What I want to do is to create a simple class which already has the order I want no matter the sequence of filling it.

I checked this questionHow to create an OrderedDict in Python?, but this assumes I have the values first hand.

i.e what I want info = my_dict() #already has the sequence (order) built in

Piggydog
  • 21
  • 1
  • 6
  • 1
    Cant you define some default None value for keys wich are yet to update ? – Vaibhav Aug 30 '19 at 11:28
  • 1
    also as of 3.7 'normal `dict` is also ordered. – buran Aug 30 '19 at 11:29
  • 1
    Why does the order matter if the keys are fixed values? – Thierry Lathuille Aug 30 '19 at 11:29
  • @ThierryLathuille I yield the dictionaries to `CSVExporter`. – Piggydog Aug 30 '19 at 11:31
  • @Vaibhav Yes, but is that the "pythonic" way of doing it? – Piggydog Aug 30 '19 at 11:32
  • I don't know about CSVExporter (and couldn't find anything about such a thing after googling it...). What is it exactly? (can you share some link to its documentation?) And are you sure that it expects an ordereddict to be used? – Thierry Lathuille Aug 30 '19 at 11:38
  • @ThierryLathuille [https://doc.scrapy.org/en/latest/topics/feed-exports.html], it can take in any sort of dictionary,but when I am passing different ordered dict, it gives not ideal results – Piggydog Aug 30 '19 at 11:40
  • Firsly, you use some `item` dict but your function gets `my_dict`. Secondly, for getting item or a default value use `my_dict.get(k, default_value_here)` – h4z3 Aug 30 '19 at 11:40
  • 1
    The doc you linked to says 'To specify columns to export and their order use FEED_EXPORT_FIELDS', which is a list of field names. That would be the normal, logical way for the library you use to know the order of fields. Maybe you should ask a question with your real practical problem. – Thierry Lathuille Aug 30 '19 at 11:44
  • What is the nesting structure of your dict to maintain uniqueness? Would a sorted list or JSON data be a possible option? – DaveStSomeWhere Aug 30 '19 at 11:45

1 Answers1

0

As I understand you want to have a data structure that gives you the same operations as dict, but if iterate over gives items in a precise order.

If this is the case you can override the methods that gives out iterables: the __iter__ method, the key method, the values method and the items method (maybe there are others which I can't remember)

There is a basic class you can start off. (I.e this will only iterate over the elements you specified, but probably you want to extend to iterate over the other elements, too)

from collections import UserDict

class MyDict(UserDict):
    def __init__(self, *args, **kwargs):
        self.order = kwargs.pop('order')
        super().__init__(*args)
    def change_order(self, order: list):
        self.order = order

    def __iter__(self):
        for key in self.order:
            if key in self:
                yield key

    def keys(self):
        for key in self.order:
            if key in self:
                yield key

    def values(self):
        for key in self.order:
            if key in self:
                yield self[key]

    def items(self):
        for key in self.order:
            if key in self:
                yield key, self[key]

There is a test:

d = MyDict({"b" : 2, "c": 3, "a": 1}, order=["a","b","c"])
print(d)

for k in d:
    print(k, end=" ")
#a b c
print()

for k in d.keys():
    print(k, end=" ")
#a b c
print()

for v in d.values():
    print(v, end=" ")
#1 2 3
print()

for k, v in d.items():
    print(f"{k}-{v}", end=" ")
#a-1 b-2 c-3

You can override __repr__ and __str__ if you want your dictionary to be converted in string (and printed) in the order you want, too

Marco Zamboni
  • 224
  • 1
  • 9