Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #7963 > unrolled thread

How to iterate on a changing dictionary

Started byTheSaint <nobody@nowhere.net.no>
First post2011-06-19 22:32 +0800
Last post2011-06-21 18:44 +0800
Articles 10 — 6 participants

Back to article view | Back to comp.lang.python


Contents

  How to iterate on a changing dictionary TheSaint <nobody@nowhere.net.no> - 2011-06-19 22:32 +0800
    Re: How to iterate on a changing dictionary Chris Angelico <rosuav@gmail.com> - 2011-06-20 01:13 +1000
      Re: How to iterate on a changing dictionary Roy Smith <roy@panix.com> - 2011-06-19 11:53 -0400
        Re: How to iterate on a changing dictionary Terry Reedy <tjreedy@udel.edu> - 2011-06-19 12:51 -0400
    Re: How to iterate on a changing dictionary Terry Reedy <tjreedy@udel.edu> - 2011-06-19 12:02 -0400
    Re: How to iterate on a changing dictionary Lie Ryan <lie.1296@gmail.com> - 2011-06-20 03:00 +1000
      Re: How to iterate on a changing dictionary TheSaint <nobody@nowhere.net.no> - 2011-06-20 21:20 +0800
        Re: How to iterate on a changing dictionary Florencio Cano <florencio.cano@gmail.com> - 2011-06-20 16:30 +0200
        Re: How to iterate on a changing dictionary Terry Reedy <tjreedy@udel.edu> - 2011-06-20 13:37 -0400
          Re: How to iterate on a changing dictionary TheSaint <nobody@nowhere.net.no> - 2011-06-21 18:44 +0800

#7963 — How to iterate on a changing dictionary

FromTheSaint <nobody@nowhere.net.no>
Date2011-06-19 22:32 +0800
SubjectHow to iterate on a changing dictionary
Message-ID<itl1a5$rom$1@speranza.aioe.org>
Hello

Trying to pop some key from a dict while is iterating over it will cause an 
exception.
How I can remove items when the search result is true.

Example:

while len(dict):
   for key in dict.keys():
      if dict[key] is not my_result:
         dict.pop(key)
    else:
       condition_to_break
print('Dictionary is over')

this is my mistake, but where to fix?
-- 
goto /dev/null

[toc] | [next] | [standalone]


#7969

FromChris Angelico <rosuav@gmail.com>
Date2011-06-20 01:13 +1000
Message-ID<mailman.154.1308496441.1164.python-list@python.org>
In reply to#7963
On Mon, Jun 20, 2011 at 12:32 AM, TheSaint <nobody@nowhere.net.no> wrote:
> Hello
>
> Trying to pop some key from a dict while is iterating over it will cause an
> exception.
> How I can remove items when the search result is true.
>
> Example:
>
> while len(dict):
>   for key in dict.keys():
>      if dict[key] is not my_result:
>         dict.pop(key)
>    else:
>       condition_to_break
> print('Dictionary is over')

One way is to iterate over an explicitly formed list of the keys.

for key in list(dict.keys()):

That creates an entirely new list with a snapshot copy of the keys. If
you then remove elements from the dictionary, the list will still
iterate correctly.

I'm not sure what you're trying to do, but you may find it easier to
use the 'filter' function (which takes an iterable, so possibly use
dict.iteritems() for that).It'll keep some and not others, and then
you can make use of just the ones you get back.

Chris Angelico

[toc] | [prev] | [next] | [standalone]


#7974

FromRoy Smith <roy@panix.com>
Date2011-06-19 11:53 -0400
Message-ID<roy-3DDD62.11534419062011@news.panix.com>
In reply to#7969
In article <mailman.154.1308496441.1164.python-list@python.org>,
 Chris Angelico <rosuav@gmail.com> wrote:

> On Mon, Jun 20, 2011 at 12:32 AM, TheSaint <nobody@nowhere.net.no> wrote:
> > Hello
> >
> > Trying to pop some key from a dict while is iterating over it will cause an
> > exception.
> > How I can remove items when the search result is true.
> >
> > Example:
> >
> > while len(dict):
> >   for key in dict.keys():
> >      if dict[key] is not my_result:
> >         dict.pop(key)
> >    else:
> >       condition_to_break
> > print('Dictionary is over')
> 
> One way is to iterate over an explicitly formed list of the keys.
> 
> for key in list(dict.keys()):
> 
> That creates an entirely new list with a snapshot copy of the keys. If
> you then remove elements from the dictionary, the list will still
> iterate correctly.

If the dict is large and you only want to remove a relatively small 
number of keys, you could instead build up a list of keys to be deleted 
and do them in a second pass:

# pseudo-code
pending_keys = []
for key in dict.keys():
  if dict[key] is not my_result:
    pending_keys.append(key)
for key in pending_keys:
  del dict[key]

Yet another variation which makes sense if you want to delete most of 
the keys would be to copy them to a new dictionary.  I'm not sure how 
Python handles memory management on dictionaries which shrink.  I'm 
guessing it doesn't do anything about resizing the hash table downwards, 
so you end up with a lot of wasted space.  This solves that problem:

# pseudo-code
new_dict = {}
for key in dict.keys():
  if dict[key] is my_result:
    new_dict[key] = dict[key]

although you could improve on that with iteritems() instead of keys().

Of course, of all these, Chris Angelico's original code is the most 
straight-forward, and that's would I would use unless you had some 
strong reason to believe performance was an issue.

[toc] | [prev] | [next] | [standalone]


#7982

FromTerry Reedy <tjreedy@udel.edu>
Date2011-06-19 12:51 -0400
Message-ID<mailman.161.1308502281.1164.python-list@python.org>
In reply to#7974
On 6/19/2011 11:53 AM, Roy Smith wrote:

> Yet another variation which makes sense if you want to delete most of
> the keys would be to copy them to a new dictionary.  I'm not sure how
> Python handles memory management on dictionaries which shrink.

'Python' does not handle memory management; each implementation does -).
I believe CPython will shrink lists and dicts that are too empty, but it 
should be both more efficient and more dependable to make a new one as 
with your code or

old_d = {i:i for i in range(100)}
d = {key:val for key,val in old_d.items() if not key%13}
d
 >>>
{0: 0, 65: 65, 39: 39, 13: 13, 78: 78, 52: 52, 26: 26, 91: 91}

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#7976

FromTerry Reedy <tjreedy@udel.edu>
Date2011-06-19 12:02 -0400
Message-ID<mailman.157.1308499346.1164.python-list@python.org>
In reply to#7963
On 6/19/2011 11:13 AM, Chris Angelico wrote:
> On Mon, Jun 20, 2011 at 12:32 AM, TheSaint<nobody@nowhere.net.no>  wrote:
>> Hello
>>
>> Trying to pop some key from a dict while is iterating over it will cause an
>> exception.
>> How I can remove items when the search result is true.
>>
>> Example:
>>
>> while len(dict):
>>    for key in dict.keys():
>>       if dict[key] is not my_result:
>>          dict.pop(key)
>>     else:
>>        condition_to_break
>> print('Dictionary is over')
>
> One way is to iterate over an explicitly formed list of the keys.
>
> for key in list(dict.keys()):
>
> That creates an entirely new list with a snapshot copy of the keys. If
> you then remove elements from the dictionary, the list will still
> iterate correctly.

The other is to make a set of to_be_deleted keys and delete them all 
when done.

If you only want to delete one key, break the iteration and then delete.

> I'm not sure what you're trying to do,  but you may find it easier to
> use the 'filter' function (which takes an iterable, so possibly use
> dict.iteritems() for that).It'll keep some and not others, and then
> you can make use of just the ones you get back.



-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#7986

FromLie Ryan <lie.1296@gmail.com>
Date2011-06-20 03:00 +1000
Message-ID<4dfe2b95$1@dnews.tpgi.com.au>
In reply to#7963
On 06/20/11 00:32, TheSaint wrote:
> Hello
> 
> Trying to pop some key from a dict while is iterating over it will cause an 
> exception.
> How I can remove items when the search result is true.
> 
> Example:
> 
> while len(dict):
>    for key in dict.keys():
>       if dict[key] is not my_result:
>          dict.pop(key)
>     else:
>        condition_to_break
> print('Dictionary is over')


Others has described how to do what you wanted to do, but let's address
the main problem here, why are you iterating a dictionary?

I found that most of the time that I thought I needed to iterate through
a dictionary, it's really because I'm thinking the wrong way, and a
little bit more thought lead me to a better way that doesn't involve
iterating on the dictionary.

While there are legitimate reasons for iterating a dictionary, I'd
consider the alternatives first.

[toc] | [prev] | [next] | [standalone]


#8013

FromTheSaint <nobody@nowhere.net.no>
Date2011-06-20 21:20 +0800
Message-ID<itnhfp$ab0$1@speranza.aioe.org>
In reply to#7986
Lie Ryan wrote:

Thank you all for the information, really apreciated.

> While there are legitimate reasons for iterating a dictionary, I'd
> consider the alternatives first.

Perhaps the correct answer is in what you said.

For certain reasons, searching in a dictionary is the fastest method, 
secondly the positions of the data aren't relevant and easy to find.

My primer purpose is to know how much of work is done as soon the child 
process reports completion of a part. The order of the given jobs are not 
linear as it could do with a list.

To make an example: imaging Bingo.Shuffle the numbers, each number sorted 
should be removed from the container, how would it implemented?

-- 
goto /dev/null

[toc] | [prev] | [next] | [standalone]


#8015

FromFlorencio Cano <florencio.cano@gmail.com>
Date2011-06-20 16:30 +0200
Message-ID<mailman.182.1308580256.1164.python-list@python.org>
In reply to#8013
> To make an example: imaging Bingo.Shuffle the numbers, each number sorted
> should be removed from the container, how would it implemented?

The structure seems a set -> unordered collection of unique elements.

You can select a random element from the set with
random.sample(container, num_of_elems)

And then remove the elem from the set with remove.

[toc] | [prev] | [next] | [standalone]


#8020

FromTerry Reedy <tjreedy@udel.edu>
Date2011-06-20 13:37 -0400
Message-ID<mailman.184.1308591490.1164.python-list@python.org>
In reply to#8013
On 6/20/2011 10:30 AM, Florencio Cano wrote:
>> To make an example: imaging Bingo.Shuffle the numbers, each number sorted
>> should be removed from the container, how would it implemented?
>
> The structure seems a set ->  unordered collection of unique elements.
>
> You can select a random element from the set with
> random.sample(container, num_of_elems)
>
> And then remove the elem from the set with remove.

random.sample(someset) just turns the set into a sequence (tuple).
For bingo, where you will play multiple games,
start with an immutable collection balls = ('A1', 'A2', ...)
that you cannot accidentally modify and can repeatedly copy.
For each game, copy to a list game = list(balls).
Then random.shuffle(game), and game.pop() balls as needed.

Other situations will need other solutions.

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#8082

FromTheSaint <nobody@nowhere.net.no>
Date2011-06-21 18:44 +0800
Message-ID<itpslk$cq4$1@speranza.aioe.org>
In reply to#8020
Terry Reedy wrote:

> Other situations will need other solutions.
> 
Like a job's completion list.

Some number of workers get a job, and by time the caller sould know who and 
what has finished. Then a dictionary would hold number of remaining jobs.
Similar a downloading list.

-- 
goto /dev/null

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web