Order of elements in a dict

  • Thread starter Marcio Rosa da Silva
  • Start date
M

Marcio Rosa da Silva

Hi!

In dictionaries, unlinke lists, it doesn't matter the order one inserts
the contents, elements are stored using its own rules.

Ex:
{1: 2, 3: 4}

So, my question is: if I use keys() and values() it will give me the
keys and values in the same order?

In other words, it is safe to do:

to exchange keys and values on a dictionary? Or I can have the values
and keys in a different order and end with something like this:
{2: 3 , 4: 1}

instead of:
{2: 1, 4: 3}

For this example it works as I wanted (the second output), but can I
trust this?

Also, if someone has a better way to exchange keys and values in a dict,
I would like to learn. :)

Thanks!

Marcio
 
F

Fredrik Lundh

Marcio said:
In dictionaries, unlinke lists, it doesn't matter the order one inserts the contents, elements are
stored using its own rules.

Ex:

{1: 2, 3: 4}

So, my question is: if I use keys() and values() it will give me the keys and values in the same
order?

http://docs.python.org/lib/typesmapping.html

"Keys and values are listed in an arbitrary order which is non-random,
varies across Python implementations, and depends on the dictionary's
history of insertions and deletions. If items(), keys(), values(), iteritems(),
iterkeys(), and itervalues() are called with no intervening modifications
to the dictionary, the lists will directly correspond."

</F>
 
P

Peter Otten

Marcio said:
In other words, it is safe to do:

Yes, if the dictionary isn't modified between the invocation of values() and
keys(). Quoting http://docs.python.org/lib/typesmapping.html

"""
Keys and values are listed in an arbitrary order which is non-random, varies
across Python implementations, and depends on the dictionary's history of
insertions and deletions. If items(), keys(), values(), iteritems(),
iterkeys(), and itervalues() are called with no intervening modifications
to the dictionary, the lists will directly correspond. This allows the
creation of (value, key) pairs using zip(): "pairs = zip(a.values(),
a.keys())". The same relationship holds for the iterkeys() and itervalues()
methods: "pairs = zip(a.itervalues(), a.iterkeys())" provides the same
value for
"""

I suppose you are aware that you lose information if multiple keys have the
same value.

Peter
 
D

Duncan Booth

Marcio said:
In other words, it is safe to do:


to exchange keys and values on a dictionary?

See the Library Reference, section 2.3.8 Mapping Types:
Keys and values are listed in an arbitrary order which is non-random,
varies across Python implementations, and depends on the dictionary's
history of insertions and deletions. If items(), keys(), values(),
iteritems(), iterkeys(), and itervalues() are called with no
intervening modifications to the dictionary, the lists will directly
correspond. This allows the creation of (value, key) pairs using
zip(): "pairs = zip(a.values(), a.keys())". The same relationship
holds for the iterkeys() and itervalues() methods: "pairs =
zip(a.itervalues(), a.iterkeys())" provides the same value for pairs.
Another way to create the same list is "pairs = [(v, k) for (k, v) in
a.iteritems()]".
 
L

Leif K-Brooks

Marcio said:
So, my question is: if I use keys() and values() it will give me the
keys and values in the same order?

It should work fine with the current implementation of dictionaries, but
(AFAIK) it's not guaranteed to work by the mapping protocol. So
theoretically, it could break under Python 2.5 or with a user-made
mapping type.
Also, if someone has a better way to exchange keys and values in a dict,
I would like to learn. :)

I would do it like this:
>>> d = {1: 2, 2: 3, 3: 4}
>>> d = dict([(value, key) for key, value in d.iteritems()])
>>> d
{2: 1, 3: 2, 4: 3}
 
P

Paul McGuire

Here is a brute-force list comprehension that does not depend on
preserving order between dict.keys() and dict.values():

dict( [ (a[1],a[0]) for a in d.items() ] )

Or for map/lambda lovers:

rev = lambda a: (a[1],a[0])
dict( map( rev, d.items() )

But you still have no control over the order returned by d.items(), so
if your initial dict has duplicate values, there is no telling which
key a duplicate would map to.

The real general-purpose dict inversion results in a dict with each
value containing a list of keys in the original dict that mapped to the
given value. That is:
d = {3: 4, 1: 2, 0:4}
would invert to:
d2 = { 2:[1], 4:[0,3] }

I couldn't cram this into a list comp, so here is a short for loop to
create d2:
d2 = {}
for k,v in d.items():
d2[v] = d2.get(v, list()) + [k]

-- Paul
 
S

Steve Holden

Marcio said:
Hi!

In dictionaries, unlinke lists, it doesn't matter the order one inserts
the contents, elements are stored using its own rules.

Ex:

{1: 2, 3: 4}

So, my question is: if I use keys() and values() it will give me the
keys and values in the same order?

In other words, it is safe to do:


to exchange keys and values on a dictionary? Or I can have the values
and keys in a different order and end with something like this:

{2: 3 , 4: 1}

instead of:

{2: 1, 4: 3}

For this example it works as I wanted (the second output), but can I
trust this?

Also, if someone has a better way to exchange keys and values in a dict,
I would like to learn. :)

Thanks!

Marcio

Well, a footnote to the "Mapping types" page in the Library Reference says

"""Keys and values are listed in an arbitrary order which is non-random,
varies across Python implementations, and depends on the dictionary's
history of insertions and deletions. If items(), keys(), values(),
iteritems(), iterkeys(), and itervalues() are called with no intervening
modifications to the dictionary, the lists will directly correspond.
This allows the creation of (value, key) pairs using zip(): "pairs =
zip(a.values(), a.keys())". The same relationship holds for the
iterkeys() and itervalues() methods: "pairs = zip(a.itervalues(),
a.iterkeys())" provides the same value for pairs. Another way to create
the same list is "pairs = [(v, k) for (k, v) in a.iteritems()]". """

So it looks as though you will be safe, since there's a promise in the
documentation.

If you just want to iterate over the (key, value) pairs, however, you
should normally choose items() or iteritems() to do so. Then you could
use (for example):

dd = dict((x[1], x[0]) for x in d.items())

I presume you are confident that each value will only occur once in the
original dictionary, as otherwise the result will be smaller than the input.

regards
Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top