Jon Crump | 14 May 21:01

basic lists and loops question

Something basic about lists and loops that I'm not getting here. I've got 
a long list of dictionaries that looks like this:

lst = [{'placename': u'Stow, Lincolnshire', 'long-name': u'Stow, 
Lincolnshire.', 'end': datetime.date(1216, 9, 28), 'start': 
datetime.date(1216, 9, 26)},
{'placename': u'Lincoln, Lincolnshire', 'long-name': u'Lincoln, 
Lincolnshire.', 'end': datetime.date(1216, 9, 30), 'start': 
datetime.date(1216, 9, 28)},
{'placename': u'Lincoln, Lincolnshire', 'long-name': u'Lincoln, 
Lincolnshire.', 'end': datetime.date(1216, 10, 2), 'start': 
datetime.date(1216, 10, 1)},
{'placename': u'Grimsby, Lincolnshire', 'long-name': u'Grimsby, 
Lincolnshire.', 'end': datetime.date(1216, 10, 4), 'start': 
datetime.date(1216, 10, 3)},
{'placename': u'Louth, Lincolnshire', 'long-name': u'Louth, 
Lincolnshire.', 'end': datetime.date(1216, 10, 4), 'start': 
datetime.date(1216, 10, 4)}
]

I have a function that searches through them to find pairs of dictionaries 
that satisfy certain criteria. When the nested loops find such a pair, I 
need to merge them. So far so good. This works:

def events(data):
   evts = []
   for x in lst:
     for y in lst:
       if (x['placename'] == y['placename']) and (x['end'].month + 1 == 
y['start'].month) and (y['start'] - x['end'] == datetime.timedelta(1)):
(Continue reading)

bob gailer | 14 May 23:12
Picon

Re: basic lists and loops question

Jon Crump wrote:
> Something basic about lists and loops that I'm not getting here. I've 
> got a long list of dictionaries that looks like this:
>
> lst = [{'placename': u'Stow, Lincolnshire', 'long-name': u'Stow, 
> Lincolnshire.', 'end': datetime.date(1216, 9, 28), 'start': 
> datetime.date(1216, 9, 26)},
> {'placename': u'Lincoln, Lincolnshire', 'long-name': u'Lincoln, 
> Lincolnshire.', 'end': datetime.date(1216, 9, 30), 'start': 
> datetime.date(1216, 9, 28)},
> {'placename': u'Lincoln, Lincolnshire', 'long-name': u'Lincoln, 
> Lincolnshire.', 'end': datetime.date(1216, 10, 2), 'start': 
> datetime.date(1216, 10, 1)},
> {'placename': u'Grimsby, Lincolnshire', 'long-name': u'Grimsby, 
> Lincolnshire.', 'end': datetime.date(1216, 10, 4), 'start': 
> datetime.date(1216, 10, 3)},
> {'placename': u'Louth, Lincolnshire', 'long-name': u'Louth, 
> Lincolnshire.', 'end': datetime.date(1216, 10, 4), 'start': 
> datetime.date(1216, 10, 4)}
> ]
>
> I have a function that searches through them to find pairs of 
> dictionaries that satisfy certain criteria. When the nested loops find 
> such a pair, I need to merge them. So far so good. This works:
>
> def events(data):
>   evts = []
>   for x in lst:
>     for y in lst:
>       if (x['placename'] == y['placename']) and (x['end'].month + 1 == 
(Continue reading)

Jon Crump | 15 May 00:03

Re: basic lists and loops question

Bob, and Kent, Many thanks!

> Sounds like the key 'processed' is created by the assignment x['processed'] = 
> True. So those dictionaries that have not experienced this assignment have no 
> such key. You should instead use: if  'processed' in x:

Doh! Now that WAS obvious

> Try lst.remove(x)

Now this was odd. My trusty guide "Learning Python" (Lutz & Ascher) 2nd 
Ed. for python 2.3 says nothing about remove(). This must be 2.4 or 2.5 
yes?

this now has the desired effect (remains to be seen if it works for all 
instances):

def events(data):
   evts = []
   for x in data:
     for y in data:
       if (x['placename'] == y['placename']) and (x['end'].month + 1 == 
y['start'].month) and (y['start'] - x['end'] == datetime.timedelta(1)):
         x['end'] = y['end']
         data.remove(x)
     evts.append(x)
   return evts

I understand about removing elements from a container you're iterating. Is 
data.remove(x) problematic in this context?
(Continue reading)

Kent Johnson | 15 May 03:06
Gravatar

Re: basic lists and loops question

On Wed, May 14, 2008 at 6:03 PM, Jon Crump <jjcrump <at> myuw.net> wrote:
> def events(data):
>  evts = []
>  for x in data:
>    for y in data:
>      if (x['placename'] == y['placename']) and (x['end'].month + 1 ==
> y['start'].month) and (y['start'] - x['end'] == datetime.timedelta(1)):
>        x['end'] = y['end']
>        data.remove(x)
>    evts.append(x)
>  return evts
>
> I understand about removing elements from a container you're iterating. Is
> data.remove(x) problematic in this context?

Yes. It can cause the iteration to skip elements ofthe list. Better to
post-process the list with a list comprehension:
evts = [ evt for evt in evts if 'processed' not in evt ]

Kent
_______________________________________________
Tutor maillist  -  Tutor <at> python.org
http://mail.python.org/mailman/listinfo/tutor

Kent Johnson | 15 May 03:30
Gravatar

Re: basic lists and loops question

On Wed, May 14, 2008 at 9:06 PM, Kent Johnson <kent37 <at> tds.net> wrote:

>> I understand about removing elements from a container you're iterating. Is
>> data.remove(x) problematic in this context?
>
> Yes. It can cause the iteration to skip elements of the list.

For example:
In [1]: l=range(5)
In [2]: for i in l:
   ...:     print i
   ...:     if i==2:
   ...:         l.remove(i)
   ...:
   ...:
0
1
2
4

Notice how 3 is skipped. Don't do this!

Kent
_______________________________________________
Tutor maillist  -  Tutor <at> python.org
http://mail.python.org/mailman/listinfo/tutor

Jon Crump | 15 May 04:25

Re: basic lists and loops question

Kent,

On Wed, 14 May 2008, Kent Johnson wrote:
>> I understand about removing elements from a container you're iterating. Is
>> data.remove(x) problematic in this context?
>
> Yes. It can cause the iteration to skip elements ofthe list. Better to
> post-process the list with a list comprehension:
> evts = [ evt for evt in evts if 'processed' not in evt ]

Thanks very much. This became clear when I applied the .remove(x) solution 
to the whole list: very strange results. Altering x in the y loop also had 
unforseen effects. I finally decorated every dictionary acted upon so I 
could check everything that was going on. the appended merged dict got a 
"merged" key and the two dictionaries that were merged each got a 
"processed" key, then I post processed the list to remove the 'processed' 
dictionaries **whew**. Thanks for clarifying AND saving me from error.

Jon
_______________________________________________
Tutor maillist  -  Tutor <at> python.org
http://mail.python.org/mailman/listinfo/tutor

Kent Johnson | 14 May 23:31
Gravatar

Re: basic lists and loops question

On Wed, May 14, 2008 at 3:02 PM, Jon Crump <jjcrump <at> myuw.net> wrote:
> Something basic about lists and loops that I'm not getting here.
>  I have a function that searches through them to find pairs of dictionaries
> that satisfy certain criteria. When the nested loops find such a pair, I
> need to merge them. So far so good. This works:
>
>  def events(data):
>   evts = []
>   for x in lst:
>     for y in lst:
>       if (x['placename'] == y['placename']) and (x['end'].month + 1 ==
> y['start'].month) and (y['start'] - x['end'] == datetime.timedelta(1)):
>         evts.append({'placename': x['placename'], 'long-name':
> x['long-name'], 'start': x['start'], 'end': y['end']})
>     evts.append(x)
>   return evts
>
>  for x in events(lst):
>   print x
>
>  But then I need to delete the two original dictionaries that I merged. If I
> do del x, I get an error "local variable 'x' referenced before assignment"

Not sure why you got that error but it general it is not a good idea
to delete items from a container you are iterating; the results can be
unpredictable.
>
>  I've also tried decorating the processed dictionaries in the if loop thus:
>  x['processed'] = True
>  y['processed'] = True
(Continue reading)


Gmane