Removing dictionary-keys not in a set?

  • Thread starter Tim N. van der Leeuw
  • Start date
T

Tim N. van der Leeuw

Hi,

I'd like to remove keys from a dictionary, which are not found in a
specific set. So it's kind of an intersection-operation.

I can create a new dictionary, or a loop over all keys and test them
for set-membership, but I was wondering if there was a smart way to
express this in 1 or 2 concise statements that I'm not aware of.

So are there smarter ways to get the intersection of dictionary and set
into a dictionary than the following pseudo-code:

# Variation 1
d2 = {}
for key in s: d2[key] = d1[key]

# Variation 2
for key in d.iterkeys(): if key not in s: del d[key]


And if there's no smarter way, then which of these two options would
give best performance?

Cheers,

--Tim
 
S

Satchidanand Haridas

Hi,

I am not sure if this way is a good one, but it certainly is consise.
Also sometimes, it's better to go for a simple approach than the consise
one (for readability). With the abive disclaimer, I present my solution:

d1 = {1 : 2, 3 : 4, 5 : 6, 7 : 8, 9 : 10 }
s1 = [ 1, 5, 7 ]

# assuming you are using python 2.3.5
import sets
d2 = dict( [ ( x, d1[ x ] ) for x in sets.Set( d1.keys() ).
intersection( sets.Set( s1 ) ) ] )


thanks,
Satchit
 
S

Steven Bethard

Tim said:
Hi,

I'd like to remove keys from a dictionary, which are not found in a
specific set. So it's kind of an intersection-operation.

I can create a new dictionary, or a loop over all keys and test them
for set-membership, but I was wondering if there was a smart way to
express this in 1 or 2 concise statements that I'm not aware of.

So are there smarter ways to get the intersection of dictionary and set
into a dictionary than the following pseudo-code:

# Variation 1
d2 = {}
for key in s: d2[key] = d1[key]

# Variation 2
for key in d.iterkeys(): if key not in s: del d[key]

You could try a generator expression:

py> d = {1: 2, 3: 4, 5: 6, 7: 8, 9: 10}
py> s = set([1, 5, 7])
py> dict((k, v) for k, v in d.iteritems() if k in s)
{1: 2, 5: 6, 7: 8}

Note that your variation 2 won't work:

py> for key in d.iterkeys():
.... if key not in s:
.... del d[key]
....
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
RuntimeError: dictionary changed size during iteration

You can make it work using keys() instead of iterkeys():

py> for key in d.keys():
.... if key not in s:
.... del d[key]
....
py> d
{1: 2, 5: 6, 7: 8}

But I think I'd probably lean towards the generator expression...

STeVe
 
A

Aahz

I'd like to remove keys from a dictionary, which are not found in a
specific set. So it's kind of an intersection-operation.

Why not just use the builtin set operations?
--
Aahz ([email protected]) <*> http://www.pythoncraft.com/

"The joy of coding Python should be in seeing short, concise, readable
classes that express a lot of action in a small amount of clear code --
not in reams of trivial code that bores the reader to death." --GvR
 
K

Klaus Alexander Seistrup

Tim said:
I'd like to remove keys from a dictionary, which are not found
in a specific set. So it's kind of an intersection-operation.

How about

#v+

klaus@home:~ $ python
Python 2.4.1 (#2, Mar 30 2005, 21:51:10)
[GCC 3.3.5 (Debian 1:3.3.5-8ubuntu2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
d1 = {1:'a', 2:'b', 3:'c', 4:'d', 5:'e'}
s1 = set(d1)
s1 set([1, 2, 3, 4, 5])
s2 = set([1, 3, 5])
s1-s2 set([2, 4])
for k in s1-s2:
.... del d1[k]
.... klaus@home:~ $

#v-
 
T

Tim N. van der Leeuw

Hi Aahz,

The problem with using the builtin set operations is, that the
dictionary keys don't represent a set, so you can't directly create a
new dictionary using set methods.

So I'm looking for what's a concise way to update a dictionary, or
create a new dictionary, using basically an intersection method.

(I'm using Python 2.4.1 so I do have convenient builtin set operations
available)

In my taste, using generator expressions with conditions actually
doesn't look very readable; it hides the set-membership test under the
syntactic clutter.
(I don't mind generator expressions in principle, but I do feel that
here they clutter up the intent of the code)

cheers,

--Tim
 
T

Tim N. van der Leeuw

Hi Klaus,

I think I like the looks of your version the best, so far. Readable and
clear, to me.

cheers and thanks,

--Tim
 
S

Steven Bethard

Tim said:
In my taste, using generator expressions with conditions actually
doesn't look very readable; it hides the set-membership test under the
syntactic clutter.

You might try different indentation. I find that I write a lot of my
list comprehensions and generator expressions like:

dict((k, v)
for k, v in d.iteritems()
if k in s)

It looks much more like the for-loop in my mind, and I can easily spot
each of the for- and if-expressions in the genexp.

STeVe
 
O

Oren Tirosh

Tim N. van der Leeuw said:
Hi,

I'd like to remove keys from a dictionary, which are not found in a
specific set.

Here's my magic English-to-Python translator:

"I'd like to ... keys which ..." -> "for key in"
"keys from a dictionary" -> "set(dictionary)"
"not found in a specific set" -> "-specificset"
"... remove keys ..." -> "del dictionary[key]"

Putting it all together:
.... del dictionary[key]

Oren
 
R

Raymond Hettinger

[Klaus Alexander Seistrup]
d1 = {1:'a', 2:'b', 3:'c', 4:'d', 5:'e'}
s1 = set(d1)
s1 set([1, 2, 3, 4, 5])
s2 = set([1, 3, 5])
s1-s2 set([2, 4])
for k in s1-s2:
... del d1[k]
...

FWIW, if s2 is not already a set object, it need not be transformed before using
it. Instead, write:

for k in set(d1).difference([1,3,5]):
del d1[k]

If you prefer to work with dictionaries instead of sets, then adapt the existing
code for symmetric_difference_update() in sets.py.



Raymond Hettinger
 

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,763
Messages
2,569,563
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top