Re: Iterating over dict and removing some elements
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
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
> -- 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
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
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
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
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
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
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
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
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