Updating python dictionary

John Machin sjmachin at lexicon.net
Mon Sep 8 11:20:13 CEST 2008


On Sep 8, 10:47 am, MK Bernard <mkbernard.... at gmail.com> wrote:
> On Sep 7, 3:37 pm, John Machin <sjmac... at lexicon.net> wrote:
>
>
>
>
>
> > On Sep 8, 7:51 am, "andyh... at gmail.com" <andyh... at gmail.com> wrote:
>
> > > Hello...
>
> > > I have a dict of key/values and I want to change the keys in it, based
> > > on another mapping dictionary. An example follows:
>
> > > MAPPING_DICT = {
> > >     'a': 'A',
> > >     'b': 'B',
>
> > > }
>
> > > my_dict = {
> > >     'a': '1',
> > >     'b': '2'
>
> > > }
>
> > > I want the finished my_dict to look like:
>
> > > my_dict = {
> > >     'A': '1',
> > >     'B': '2'
>
> > > }
>
> > > Whereby the keys in the original my_dict have been swapped out for the
> > > keys mapped in MAPPING_DICT.
>
> > > Is there a clever way to do this, or should I loop through both,
> > > essentially creating a brand new dict?
>
> > Is this homework?
>
> > There seems to be an implicit assumption in the answers so far that
> > your mapping is a 1:1 mapping of all possible input keys.
>
> > If it doesn't include all possible input keys, answers will crash with
> > a KeyError. If there are any many:1 elements in the mapping (for
> > example, {'a': 'A', 'b': 'A'}), lossage happens. You may wish to code
> > in some checks for this.
>
> Thats exactly why I did an explicit check in my post, so as to make
> sure that such a collision could not occur. It would seem that
> something along what I posted would be safer, if less elegant, than
> the others.

I noted two problems:
(1) not covering all input keys: your code explicitly sweeps this
problem under the carpet, and does it laboriously ...
    if x in my_dict.keys():
instead of
    if x in my_dict:
(2) not a 1:1 mapping -- for example, 'a' and 'b' both map to 'A' (the
only "collision" that I can see), but you don't address that.

Here's some code which attempts to cover the bases:

new_dict = {}
for key in my_dict:
    if key not in MAPPING_DICT:
        raise NoMapError('blah %r' % key)
    else:
        new_key = MAPPING_DICT[key]
    if new_key in new_dict:
        raise ManyToOneError('gurgle %r waffle %r' % (key, new_key))
    else:
        new_dict[new_key] = my_dict[key]

Having considered what is actually required under the checked-for
conditions, one or both raise statements may be replaced by other
code, and then simplified e.g. the first 4 lines in the loop may end
up being replaced by
    new_key = MAPPING_DICT.get(key, key)
as already suggested by one respondent.

Note that useful use-cases for any variety of this key-change exercise
may have many more items in MAPPING_DICT than there are in my_dict (a
big language dictionary and a few fragments of text to be
"translated"), or vice versa (a small synonym dictionary (color ->
colour, center -> centre) and a big input to be "standardised") so
it's a good idea to inquire which is likely to be the smaller and
iterate over that if the requirements permit it.



More information about the Python-list mailing list