Inverse of dict(zip(x,y))

L

lone_eagle

Hi all,

This might be trivial ...

Can someone suggest a easy method to do the inverse of dict(zip(x,y))
to get two lists x and y?

So, if x and y are two lists, it is easier to make a dictionary using
d = dict(zip(x,y)), but if I have d of the form, d = {x1:y1,
x2:y2, ...}, what is there any trick to get lists x = [x1, x2, ...]
and y = [y1, y2, ...]

Cheers,
Chaitanya.
 
P

Paul Rubin

lone_eagle said:
So, if x and y are two lists, it is easier to make a dictionary using
d = dict(zip(x,y)), but if I have d of the form, d = {x1:y1,
x2:y2, ...}, what is there any trick to get lists x = [x1, x2, ...]
and y = [y1, y2, ...]

This may be a bit of a mind bender, but:

x, y = zip(*d.items())

The trick is that if xys is a list of pairs, then zip(*xys) splits
out the pairs, e.g.:
[(1, 3, 5), (2, 4, 6)]

I found that in the python docs somewhere. The mind wobbles.
 
A

Andreas Tawn

Can someone suggest a easy method to do the inverse of dict(zip(x,y))
to get two lists x and y?

So, if x and y are two lists, it is easier to make a dictionary using
d = dict(zip(x,y)), but if I have d of the form, d = {x1:y1,
x2:y2, ...}, what is there any trick to get lists x = [x1, x2, ...]
and y = [y1, y2, ...]

Cheers,
Chaitanya.

x = d.keys()
y = d.values()

Cheers,
Drea
 
A

Andre Engels

Can someone suggest a easy method to do the inverse of dict(zip(x,y))
to get two lists x and y?

So, if x and y are two lists, it is easier to make a dictionary using
d = dict(zip(x,y)), but if I have d of the form, d = {x1:y1,
x2:y2, ...}, what is there any trick to get lists x = [x1, x2, ...]
and y = [y1, y2, ...]

x = d.keys()
y = [d[e] for d in x]

y = d.values() might also work, but I am not sure whether d.keys() and
d.values() are guaranteed to use the same order.
 
P

psykeedelik

lone_eagle said:
So, if x and y are two lists, it is easier to make a dictionary using
d = dict(zip(x,y)), but if I have d of the form, d = {x1:y1,
x2:y2, ...}, what is there any trick to get lists x = [x1, x2, ...]
and y = [y1, y2, ...]

This may be a bit of a mind bender, but:

  x, y = zip(*d.items())

The trick is that if xys is a list of pairs, then zip(*xys) splits
out the pairs, e.g.:

     >>> zip(*((1,2),(3,4),(5,6)))
     [(1, 3, 5), (2, 4, 6)]

I found that in the python docs somewhere.  The mind wobbles.

That was cool!!

I just checked the python documentation, but the below note worries me
a bit!!

"""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....."""

I hope it does not mean that the key->value mapping is not guaranteed,
but only that the order of the [key: value] pairs would change. Which
one is right?

Cheers,
Chaitanya
 
P

Peter Otten

Andreas said:
Can someone suggest a easy method to do the inverse of dict(zip(x,y))
to get two lists x and y?

So, if x and y are two lists, it is easier to make a dictionary using
d = dict(zip(x,y)), but if I have d of the form, d = {x1:y1,
x2:y2, ...}, what is there any trick to get lists x = [x1, x2, ...]
and y = [y1, y2, ...]

Cheers,
Chaitanya.

x = d.keys()
y = d.values()

But be aware that lose order and of course duplicate keys:
d = dict(zip("abca", "xyzt"))
d.keys() ['a', 'c', 'b']
d.values()
['t', 'z', 'y']

See also the note for the dict.items() method at
http://docs.python.org/library/stdtypes.html#mapping-types-dict

Peter
 
P

Peter Otten

Andreas said:
Can someone suggest a easy method to do the inverse of dict(zip(x,y))
to get two lists x and y?

So, if x and y are two lists, it is easier to make a dictionary using
d = dict(zip(x,y)), but if I have d of the form, d = {x1:y1,
x2:y2, ...}, what is there any trick to get lists x = [x1, x2, ...]
and y = [y1, y2, ...]

Cheers,
Chaitanya.

x = d.keys()
y = d.values()

But be aware that you lose order and of course duplicate keys:
d = dict(zip("abca", "xyzt"))
d.keys() ['a', 'c', 'b']
d.values()
['t', 'z', 'y']

See also the note for the dict.items() method at
http://docs.python.org/library/stdtypes.html#mapping-types-dict

Peter
 
H

Hrvoje Niksic

psykeedelik said:
"""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....."""

I hope it does not mean that the key->value mapping is not
guaranteed, but only that the order of the [key: value] pairs would
change. Which one is right?

The latter, of course. The documentation is trying to warn you not to
rely on the order of returned pairs, not imply that the items() method
is unusable.
 
L

Lie Ryan

Andre said:
y = d.values() might also work, but I am not sure whether d.keys() and
d.values() are guaranteed to use the same order.

If they were called immediately after each other I think they should,
but better not rely on it.
 
A

Andreas Tawn

So, if x and y are two lists, it is easier to make a dictionary using
d = dict(zip(x,y)), but if I have d of the form, d = {x1:y1,
x2:y2, ...}, what is there any trick to get lists x = [x1, x2, ...]
and y = [y1, y2, ...]

Cheers,
Chaitanya.

x = d.keys()
y = d.values()

But be aware that you lose order and of course duplicate keys:

True, but that's a result of creating the dictionary, not extracting the
keys and values later.
{'a': 't', 'c': 'z', 'b': 'y'}
 
P

Piet van Oostrum

Andre Engels said:
Can someone suggest a easy method to do the inverse of dict(zip(x,y))
to get two lists x and y?

So, if x and y are two lists, it is easier to make a dictionary using
d = dict(zip(x,y)), but if I have d of the form, d = {x1:y1,
x2:y2, ...}, what is there any trick to get lists x = [x1, x2, ...]
and y = [y1, y2, ...]
AE> x = d.keys()
AE> y = [d[e] for d in x]
AE> y = d.values() might also work, but I am not sure whether d.keys() and
AE> d.values() are guaranteed to use the same order.

Yes, they are if the dictionary is not changed in the meantime (not even
inserting and removing the same thing). See the library documentation,
section dict.
 
L

Lie Ryan

Lorenzo said:
zip() in conjunction with the * operator can be used to unzip a list:

That's because zip is the inverse operation of zip. I remember someone
saying that zip's typical name is transpose (like in matrix transpose).

a == zip(*zip(*a))

<nitpick> * in argument unpacking is not an operator </nitpick>
 
P

Paul McGuire

If they were called immediately after each other I think they should,
but better not rely on it.

I think this is why a solution based on d.items() is preferable - it
returns each key-value pair together.

-- Paul
 
P

Paul McGuire

If they were called immediately after each other I think they should,
but better not rely on it.

Also, it offends my efficiency/performance sensibilities to use two
separate calls to iterate over the dict twice, when there is a
perfectly good equivalent that is just as readable and iterates only
once.
 
B

Benjamin Peterson

Andre Engels said:
y = d.values() might also work, but I am not sure whether d.keys() and
d.values() are guaranteed to use the same order.

They are for the builtin dictionary type, but that requirement does not extend
to any other mapping type. (It's not a requirement of the Mapping interface.)
 
S

Steven D'Aprano

Also, it offends my efficiency/performance sensibilities to use two
separate calls to iterate over the dict twice, when there is a perfectly
good equivalent that is just as readable and iterates only once.

Sure, but if you want two lists, as the OP asked for, then you have to
iterate over it twice either way:

# method 1:
keys = dict.keys()
values = dict.values()

# method 2:
keys, values = zip(*dict.items())

First you iterate over the dict to get the items, then you iterate over
the items to split into two lists. Anyone want to take bets on which is
faster?

from timeit import Timer

d = {'a':1, 'b':2, 'c':3, 'z':26}
Timer('d.keys();d.values()', 'from __main__ import d').repeat() [1.1103789806365967, 0.90148496627807617, 0.9004051685333252]
Timer('zip(*d.items())', 'from __main__ import d').repeat()
[2.1786351203918457, 2.0767219066619873, 2.076124906539917]

For a small dict, the zip solution is about twice as slow. What about for
a bigger dict?
.... 'from __main__ import D').repeat(number=100)
[9.2809889316558838, 9.150738000869751, 9.2292399406433105].... 'from __main__ import D').repeat(number=100)
[63.850389957427979, 55.749162912368774, 61.448837041854858]



Well, I think this is clear evidence that the zip solution is a
pessimation, not an optimization.

That's what I love about Python -- my intuition about what code is faster
is so often wrong!

[only half sarcastic...]
 
P

Paul Rubin

Steven D'Aprano said:
Sure, but if you want two lists, as the OP asked for, then you have to
iterate over it twice either way:

# method 1:
keys = dict.keys()
values = dict.values()

# method 2:
keys, values = zip(*dict.items())

First you iterate over the dict to get the items, then you iterate over
the items to split into two lists. Anyone want to take bets on which is
faster?

The first way involves iterating over the dict items twice. The
second way iterates over the dict items just once, copying them to
another place; it then iterates over the copy.
 
A

Andre Engels

Still I'd like to see an application where this really matters (that
keys() and values() match in order)

I think there are many such applications, but also that in each of
those cases it's a mis-programming of something that would be done
better and more pythonic using items()...
 
P

psykeedelik

Piet said:
Can someone suggest a easy method to do the inverse of dict(zip(x,y))
to get two lists x and y?
So, if x and y are two lists, it is easier to make a dictionary using
d = dict(zip(x,y)), but if I have d of the form, d = {x1:y1,
x2:y2, ...}, what is there any trick to get lists x = [x1, x2, ...]
and y = [y1, y2, ...]
AE> x = d.keys()
AE> y = [d[e] for d in x]
AE> y = d.values() might also work, but I am not sure whether d.keys() and
AE> d.values() are guaranteed to use the same order.
Yes, they are if the dictionary is not changed in the meantime (not even
inserting and removing the same thing). See the library documentation,
section dict.

Still I'd like to see an application where this really matters (that
keys() and values() match in order)

Tino

 smime.p7s
4KViewDownload

First, thanks to all the guys who posted replies to my query!!

And then, just as an example to what Tino raised ...

I usually get properties that I compute, in a dictionary like property
= [key1: val1, key2:val2, ...] and then I usually want to plot them in
pylab, which AFAIK requires x and y as lists for the plot argument.
Then I need to get the lists [key1, key2, ...] and [val1, val2, ...].
And now I wonder if there a more efficient way doing what I described
above!! ;)

Cheers,
Chaitanya
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top