Re: Iterating over dict and removing some elements

2010-05-14 Thread Paul Rubin
Bryan  writes:
> In Python 3.X, and in Python 2.X starting with 2.4, you can drop the
> square brackets and avoid creating an extra temporary list:
>
> d = dict((k, d[k]) for k in d.keys() if not foo(k, d))

In 2.x, I think you want d.iterkeys() rather than d.keys() to avoid
making a list with all the keys.  Or you can just say

  d = dict((k, d[k]) for k in d if not foo(k, d))
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over dict and removing some elements

2010-05-14 Thread Bryan
Adi Eyal  wrote:
> > Bryan:
> > Terry Reedy wrote:
> > [...]
> >> for k in [k for k in d if d[k] == 'two']:
> >>          d.pop(k)
>
> > We have a winner.
>
> also
>
> foo = lambda k, d : d[k] == "two"
> d = dict([(k, d[k]) for k in d.keys() if not foo(k, d)])
>
> incidentally, this is marginally slower than pops and dels but has the
> benefit of not modifying the original dict if that's what you need.

Well, I guess, sure. The original problem in this tread was about
modifying the dict over which we are iterating. If you create a new
dict instead, that problem just goes away.

In Python 3.X, and in Python 2.X starting with 2.4, you can drop the
square brackets and avoid creating an extra temporary list:

d = dict((k, d[k]) for k in d.keys() if not foo(k, d))

You can also drop .keys() in Python 3.X or current Python 2.X:

d = dict((k, d[k]) for k in d if not foo(k, d))

Passing the dict to foo() seems inelegant. You could use:

foo = lambda val: val == "two"
d = dict((k, d[k]) for k in d if not foo(d[k]))

I'm sticking with my call of Terry Reedy's last solution as winner. It
solves the originally-stated problem, works correctly and efficiently
in both Python 3.X and current Python 2.X, and there is not a bracket
in it that does not need to be there.

--
--Bryan
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over dict and removing some elements

2010-05-12 Thread Adi Eyal
> -- Forwarded message --
> From: Bryan 
> To: python-l...@python.org
> Date: Tue, 11 May 2010 23:59:29 -0700 (PDT)
> Subject: Re: Iterating over dict and removing some elements
> Terry Reedy wrote:
> [...]
>> for k in [k for k in d if d[k] == 'two']:
>>          d.pop(k)
>
> We have a winner.
>

also

foo = lambda k, d : d[k] == "two"
d = dict([(k, d[k]) for k in d.keys() if not foo(k, d)])

incidentally, this is marginally slower than pops and dels but has the
benefit of not modifying the original dict if that's what you need.

Adi
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over dict and removing some elements

2010-05-12 Thread Bryan
Rebelo wrote:
> i am wondering why not like this:
>
>  >>> d = {1: 'one', 2: 'two', 3: 'three'}
>  >>> for k,v in d.items():
> ...     if k==1:
> ...          del d[k]
> ...
>  >>> d
> {2: 'two', 3: 'three'}
>  >>>

Mostly because there's no reason to get 'v' if you're not going to use
it. That may be just because you simplified the example, and if you
are working in Python 2.x and the real test for whether to delete
involves the value and not just the key, that's a reasonable solution.

On subtler issues, it constucts an unnecessarily long temporary list
in current Python 2.X, and fails in Python 3.x, as Terry Ready
explained.


--
--Bryan
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over dict and removing some elements

2010-05-12 Thread Rebelo

On 05/11/2010 05:08 PM, Ulrich Eckhardt wrote:

Hi!

I wrote a simple loop like this:

   d = {}
   ...
   for k in d:
   if some_condition(d[k]):
   d.pop(k)

If I run this, Python complains that the dictionary size changed during
iteration. I understand that the iterator relies on the internal structure
not changing, but how would I structure this loop otherwise?

My first approach was to simply postpone removing the elements, but I was
wondering if there was a more elegant solution.

Thanks!

Uli




i am wondering why not like this:

>>> d = {1: 'one', 2: 'two', 3: 'three'}
>>> for k,v in d.items():
... if k==1:
...  del d[k]
...
>>> d
{2: 'two', 3: 'three'}
>>>

--
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over dict and removing some elements

2010-05-12 Thread Bryan
Terry Reedy wrote:
[...]
> for k in [k for k in d if d[k] == 'two']:
>          d.pop(k)

We have a winner.


--
--Bryan


-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over dict and removing some elements

2010-05-11 Thread Terry Reedy

On 5/11/2010 11:29 AM, Jerry Hill wrote:

On Tue, May 11, 2010 at 11:08 AM, Ulrich Eckhardt
  wrote:

My first approach was to simply postpone removing the elements, but I was
wondering if there was a more elegant solution.


Iterate over something other than the actual dictionary, like this:

d = {1: 'one', 2: 'two', 3: 'three'}

for k in d.keys():
 if d[k] == 'two':
 d.pop(k)


This, as written, does not work in 3.1, where d.keys is a view of the 
dict. Nor does


for k in filter(lambda k: d[k] == 'two', d):
d.pop(k)

But these do

for k in list(filter(lambda k: d[k] == 'two', d)):
d.pop(k)

for k in [k for k in d if d[k] == 'two']:
d.pop(k)

Rather than make an external list of *all* keys, one only needs to make 
a list of keys to be removed, which often  will be much smaller.


Terry Jan Reedy

--
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over dict and removing some elements

2010-05-11 Thread superpollo

superpollo ha scritto:

Ulrich Eckhardt ha scritto:

Hi!

I wrote a simple loop like this:

  d = {}
  ...
  for k in d:
  if some_condition(d[k]):
  d.pop(k)

If I run this, Python complains that the dictionary size changed during
iteration. I understand that the iterator relies on the internal 
structure

not changing, but how would I structure this loop otherwise?


my first thought (untested):

use a copy of d for the if clause, then pop from the original.

bye


i mean:

>>> d = {"name":"max","surname":"zanardi","nick":"zanna"}
>>> dc = copy.copy(d)
>>> dc
{'nick': 'zanna', 'surname': 'zanardi', 'name': 'max'}
>>> for k in dc:
... if dc[k].startswith("z"):
... d.pop(k)
...
'zanna'
'zanardi'
>>> d
{'name': 'max'}
>>> dc
{'nick': 'zanna', 'surname': 'zanardi', 'name': 'max'}
>>>

bye
--
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over dict and removing some elements

2010-05-11 Thread Jerry Hill
On Tue, May 11, 2010 at 11:08 AM, Ulrich Eckhardt
 wrote:
> My first approach was to simply postpone removing the elements, but I was
> wondering if there was a more elegant solution.

Iterate over something other than the actual dictionary, like this:

d = {1: 'one', 2: 'two', 3: 'three'}

for k in d.keys():
if d[k] == 'two':
d.pop(k)


-- 
Jerry
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over dict and removing some elements

2010-05-11 Thread Michele Simionato
Or you copy the whole dictionary or you just copy the keys:

for k in d.keys():
...

or

for k in list(d):
...
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Iterating over dict and removing some elements

2010-05-11 Thread superpollo

Ulrich Eckhardt ha scritto:

Hi!

I wrote a simple loop like this:

  d = {}
  ...
  for k in d:
  if some_condition(d[k]):
  d.pop(k)

If I run this, Python complains that the dictionary size changed during
iteration. I understand that the iterator relies on the internal structure
not changing, but how would I structure this loop otherwise?


my first thought (untested):

use a copy of d for the if clause, then pop from the original.

bye
--
http://mail.python.org/mailman/listinfo/python-list