How to iterate over a Python dictionary in defined

2020-08-09 10:30发布

问题:

I'm trying to iterate over a dictionary that I have defined in a specific order, but it always iterates in a different order than what I have defined in my code. This is just a basic example of what I'm trying to do. The dictionary I'm iterating over is much larger, has much more complexly named keys, and is not in alphabetical/numerical order.

level_lookup = \
{
'PRIORITY_1' :   { 'level' : 'BAD',   'value' :   ''  },
'PRIORITY_2' :   { 'level' : 'BAD',   'value' :   ''  },
'PRIORITY_3' :   { 'level' : 'BAD',   'value' :   ''  },
'PRIORITY_4' :   { 'level' : 'BAD',   'value' :   ''  },
'PRIORITY_5' :   { 'level' : 'CHECK', 'value' :   ''  },
'PRIORITY_6' :   { 'level' : 'CHECK', 'value' :   ''  },
'PRIORITY_7' :   { 'level' : 'GOOD',  'value' :   ''  },
'PRIORITY_8' :   { 'level' : 'GOOD',  'value' :   ''  },
}

for priority in level_lookup:
    if( level_lookup[ priority ][ 'value' ] == 'TRUE' ):
        set_levels += str( priority ) + '\n'

I need the order that I define the dictionary in to be preserved during iteration. My order is not alphabetical, so sorting alphabetically wouldn't really help. Is there any way to do this? I've tried `level_lookup.items(), but that doesn't maintain my order either.

回答1:

You should use an OrderedDict. It works exactly the way you want it, however you need to define it that way. Alternatively, you can have a list of keys in order, and iterate through the list and access the dictionary. Something along the lines of:

level_lookup_order = ['PRIORITY_1', 'PRIORITY_2', ...]
for key in level_lookup_order:
    if key in level_lookup:
        do_stuff(level_lookup[key])

This will be a pain to maintain, though, so I recommend you just use the OrderedDict.

As a last option, you could use 'constants'. Like,

PRIORITY_1 = 1
PRIORITY_2 = 2
...
lookup_order = {PRIORITY_1: 42, PRIORITY_2: 24, ...}


回答2:

If you're fine with using the key-sorted order:

for key in sorted(level_lookup.keys()):
    ...

That's what I generally do if the dict is provided to me, and not something I instantiate (rather than OrderedDict.



回答3:

You could use a collections.OrderedDict. If that doesn't work for you, you could sort the keys before you iterate over them:

for k in sorted(myDict, lambda k: int(k.rsplit("_",1)[1]):
    # do stuff

Note however, that this particular sorting costs linear space and O(nlogn) time. Also, it uses the coincidental numbering system "PRIORITY_N" for sorting, which may not always be valid



回答4:

Try;

for priority in sorted(level_lookup.iterkeys()):

As Jon has pointed out, keys() and iterkeys() are redundant here;

for priority in sorted(level_lookup):


回答5:

I think you would be better off not using a containg dictionary and see no compelling reason to use one in this case. Alistwould store the items in the desired order:

level_lookup = [
    {'level': 'BAD',   'value': ''    },
    {'level': 'BAD',   'value': ''    },
    {'level': 'BAD',   'value': ''    },
    {'level': 'BAD',   'value': ''    },
    {'level': 'CHECK', 'value': 'TRUE'},
    {'level': 'CHECK', 'value': 'TRUE'},
    {'level': 'GOOD',  'value': ''    },
    {'level': 'GOOD',  'value': ''    },
]

set_levels = ''
for level, priority in enumerate(level_lookup, start=1):
    if priority['value'] == 'TRUE':
        set_levels += 'PRIORITY_{!s}\n'.format(level)
print set_levels

In fact, you could write the whole thing as list comprehension:

set_levels = ('\n'.join('PRIORITY_{!s}'.format(level)
                for level, priority in enumerate(level_lookup, start=1)
                    if priority['value'] == 'TRUE'))
print set_levels