how to scrutch a dict()

P

Phlip

Not Hyp:

def _scrunch(**dict):
result = {}

for key, value in dict.items():
if value is not None: result[key] = value

return result

That says "throw away every item in a dict if the Value is None".

Are there any tighter or smarmier ways to do that? Python does so
often manage maps better than that...
 
P

Paul Rubin

Phlip said:
def _scrunch(**dict):
result = {}

for key, value in dict.items():
if value is not None: result[key] = value

return result

That says "throw away every item in a dict if the Value is None".
Are there any tighter or smarmier ways to do that? Python does so
often manage maps better than that...

Untested:

def _scrunch(**kwargs):
return dict(k,v for k,v in kwargs.iteritems() if v is not None)

Note: it's best not to use "dict" as a parameter name, since it is a
built in function (dictionary constructor). It's also a bit of a code
smell that you're using keyword args like that.
 
J

James Mills

Not Hyp:

def _scrunch(**dict):
   result = {}

   for key, value in dict.items():
       if value is not None:  result[key] = value

   return result

That says "throw away every item in a dict if the Value is None".

Are there any tighter or smarmier ways to do that? Python does so
often manage maps better than that...

Rather than creating a new dict why don't you just do:

def _scrunch(d):
for k, v in d.items():
if v is None:
del d[k]

cheers
James
 
C

Chris Rebert

Phlip said:
def _scrunch(**dict):
    result = {}

    for key, value in dict.items():
        if value is not None:  result[key] = value

    return result

That says "throw away every item in a dict if the Value is None".
Are there any tighter or smarmier ways to do that? Python does so
often manage maps better than that...

Untested:

def _scrunch(**kwargs):
  return dict(k,v for k,v in kwargs.iteritems() if v is not None)

Also, in Python 3, one can instead use a dict comprehension (see PEP
274: http://www.python.org/dev/peps/pep-0274/ ), which makes this a
bit more elegant:

result = {k:v for k,v in kwargs.items() if v is not None}

Cheers,
Chris
 
J

John Pinner

Phlip said:
def _scrunch(**dict):
    result = {}
    for key, value in dict.items():
        if value is not None:  result[key] = value
    return result
That says "throw away every item in a dict if the Value is None".
Are there any tighter or smarmier ways to do that? Python does so
often manage maps better than that...

As James has suggested, you can 'clean the dict in place (as it's
mutable), you don't have to return a whole new object.
Untested:

def _scrunch(**kwargs):
   return dict(k,v for k,v in kwargs.iteritems() if v is not None)

Note: it's best not to use "dict" as a parameter name,

Yes, likewise with any other builtin; if you use pychecker and/or
pylint routinely, they would warn you about this.
since it is a
built in function (dictionary constructor).

I don't think so:

So you're not running a function, but creating an instance of a dict.

Best wishes,

John
--
 
J

Joost Molenaar

Using a 2.7/3.x dictionary comprehension, since you don't seem to mind
creating a new dictionary:

def _scrunched(d):
    return { key: value for (key, value) in d.items() if value is not None }

Joost
 
N

Neil Cerutti

Rather than creating a new dict why don't you just do:

def _scrunch(d):
for k, v in d.items():
if v is None:
del d[k]

In Python 3, where items returns an iterator, modifying the
dictionary in this way may lead to cirrhossis of the dictionary.
Here's another idea:

for k in [k for k, v in d.items() if v is None]:
del d[k]
 
P

Phlip

for k in [k for k, v in d.items() if v is None]:
  del d[k]

Tx everyone!

And I forgot about shadowing dict(), I forgot about del d[k], and I
didn't know Python had "dict comprehensions" yet.

Anyway this one might become the winner.
 
H

Hrvoje Niksic

Joost Molenaar said:
Using a 2.7/3.x dictionary comprehension, since you don't seem to mind
creating a new dictionary:

def _scrunched(d):
    return { key: value for (key, value) in d.items() if value is not None }

Note that a dict comprehension, while convenient, is not necessary for
this to be formulated as a single expression:

def _scrunched(d):
return dict((key, value) for (key, value) in d.items() if value is not None)
 
J

John Nagle

Not Hyp:

def _scrunch(**dict):
result = {}

for key, value in dict.items():
if value is not None: result[key] = value

return result

That says "throw away every item in a dict if the Value is None".

Are there any tighter or smarmier ways to do that?

Yes.

class nonnulldict(dict) :
def __setitem__(self, k, v) :
if not (v is None) :
dict.__setitem__(self, k, v)

That creates a subclass of "dict" which ignores stores of None values.
So you never store the unwanted items at all.

John Nagle
 
E

Ethan Furman

Neil said:
Rather than creating a new dict why don't you just do:

def _scrunch(d):
for k, v in d.items():
if v is None:
del d[k]


In Python 3, where items returns an iterator, modifying the
dictionary in this way may lead to cirrhossis of the dictionary.

Not only cirrhosis, but a RuntimeError:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in _scrunch
RuntimeError: dictionary changed size during iteration

~Ethan~
 
E

Ethan Furman

John said:
Not Hyp:

def _scrunch(**dict):
result = {}

for key, value in dict.items():
if value is not None: result[key] = value

return result

That says "throw away every item in a dict if the Value is None".

Are there any tighter or smarmier ways to do that?


Yes.

class nonnulldict(dict) :
def __setitem__(self, k, v) :
if not (v is None) :
dict.__setitem__(self, k, v)

That creates a subclass of "dict" which ignores stores of None values.
So you never store the unwanted items at all.

It's going to take more work than that...

--> nnd = nonnulldict(spam='eggs', ham=None, parrot=1)
--> nnd
{'ham': None, 'parrot': 1, 'spam': 'eggs'}
--> d['more_hame'] = None
--> nnd.update(d)
--> nnd
{10000:True, 'more_hame':None, 'ham':None, 'parrot':1, 'spam':'eggs'}

Tested in both 2.5 and 3.1.

~Ethan~
 
J

John Nagle

John Nagle wrote:
class nonnulldict(dict) :
def __setitem__(self, k, v) :
if not (v is None) :
dict.__setitem__(self, k, v)

That creates a subclass of "dict" which ignores stores of None values.
So you never store the unwanted items at all.

It's going to take more work than that...

--> nnd = nonnulldict(spam='eggs', ham=None, parrot=1)
--> nnd
{'ham': None, 'parrot': 1, 'spam': 'eggs'}
--> d['more_hame'] = None
--> nnd.update(d)
--> nnd
{10000:True, 'more_hame':None, 'ham':None, 'parrot':1, 'spam':'eggs'}

You're right.


class nonnulldict(dict) :
def __init__(self, **args) :
dict.__init__(self)
for k in args :
self.__setitem__(k, args[k])
def __setitem__(self, k, v) :
if not (v is None) :
dict.__setitem__(self, k, v)


There should also be a copy constructor, so you can convert a dict to a
nonnulldict, a list or tuple of pairs to a nonnulldict, etc.
But at least this will raise an exception for those cases.

John Nagle
 
E

Ethan Furman

John said:
John Nagle wrote:
class nonnulldict(dict) :
def __setitem__(self, k, v) :
if not (v is None) :
dict.__setitem__(self, k, v)

That creates a subclass of "dict" which ignores stores of None values.
So you never store the unwanted items at all.

It's going to take more work than that...

--> nnd = nonnulldict(spam='eggs', ham=None, parrot=1)
--> nnd
{'ham': None, 'parrot': 1, 'spam': 'eggs'}
--> d['more_hame'] = None
--> nnd.update(d)
--> nnd
{10000:True, 'more_hame':None, 'ham':None, 'parrot':1, 'spam':'eggs'}

You're right.


class nonnulldict(dict) :
def __init__(self, **args) :
dict.__init__(self)
for k in args :
self.__setitem__(k, args[k])
def __setitem__(self, k, v) :
if not (v is None) :
dict.__setitem__(self, k, v)


There should also be a copy constructor, so you can convert a dict to a
nonnulldict, a list or tuple of pairs to a nonnulldict, etc.
But at least this will raise an exception for those cases.

The above takes care of the initialization bug, but not the update bug...

--> nnd = nonnulldict(spam='eggs', ham=None, parrot=1)
--> nnd
{'parrot': 1, 'spam': 'eggs'}
--> d = dict(more_ham = None)
--> nnd.update(d)
--> nnd
{'more_ham': None, 'parrot': 1, 'spam': 'eggs'}

I'm not sure what you mean by a copy constructor? The copy method
creates a new dict from the existing instance, not the other way 'round.

Basically, the dict type makes some optimizations behind the scenes, so
doesn't always call it's own __setitem__ method. You would have to
override every single method that can update the dict to catch and
discard the None valued keys.

~Ethan~
 

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,961
Messages
2,570,131
Members
46,689
Latest member
liammiller

Latest Threads

Top