How to simplify the list of dictionaries by condition?

I have a list of date object dictionaries:

{ "begin" :date object1, "end" : date object2 } .... { "begin" :date object3, "end" : date object4 } 

I want to simplify this list by condition:

 if cur.end == next.begin - datetime.timedelta(seconds=1)) cur.end = next.end delete next 

How to do it?

+7
python dictionary list
source share
2 answers

I use integers instead of datetime objects to keep the code simple, but it is trivial to modify it for your needs. Removing items from the collection during iteration will break the iterator, so you either use the second list (it may be memory intensive), or replace them instead of elements. Since your items are dictionaries, I found it safe to replace the item that you want to remove with None, and in the end just filter out the Nones.

 l=[ { "b" : 1, "e" : 2}, { "b" : 3, "e" : 5}, { "b" : 6, "e" : 7}, { "b" : 10, "e" : 12}, { "b" : 13, "e" : 20} ] for i in xrange(len(l) - 1): cur = l[i] if not cur: continue next = l[i + 1] if cur["e"] == next["b"] - 1: cur["e"] = next["e"] l[i+1] = None l = filter(None, l) print l 

Since the first version does not fully satisfy your needs, repeat the steps until more time intervals are combined. This is the inefficient and possibly the most non-pythonic piece of code today, but it does the job.

 changed = True while changed: changed = False l = filter(None, l) for i in xrange(len(l) - 1): cur = l[i] if cur is None: continue next = l[i + 1] if cur["e"] == next["b"] - 1: cur["e"] = next["e"] l[i+1] = None changed = True l = filter(None, l) print l 
+1
source share

As explained in another answer, you should not remove an item from the list while iterating over it, this can lead to a lot of problems. Another method that creates a completely new list would be -

 import datetime lisdic = [] #list of dictionaries prev = None result = [] for i in lisdic: if not prev: prev = i elif prev['end'] == i['begin'] - datetime.timedelta(seconds=1): prev['end'] = i['end'] else: result.append(prev) prev = i if prev: result.append(prev) 

It will also handle similar intervals between several dictionaries (for example, the first 3 dictionaries in the list in DEMO below).

Demo -

 >>> import datetime >>> lisdic = [{"begin":datetime.datetime(2015,10,2,10,0,0),"end":datetime.datetime(2015,10,2,10,30,0)}, ... {"begin":datetime.datetime(2015,10,2,10,30,1),"end":datetime.datetime(2015,10,2,11,0,0)}, ... {"begin":datetime.datetime(2015,10,2,11,0,1),"end":datetime.datetime(2015,10,2,12,0,0)}, ... {"begin":datetime.datetime(2015,10,3,10,0,0),"end":datetime.datetime(2015,10,3,10,30,0)}, ... {"begin":datetime.datetime(2015,10,3,11,0,0),"end":datetime.datetime(2015,10,3,11,30,0)}, ... {"begin":datetime.datetime(2015,10,4,12,0,0),"end":datetime.datetime(2015,10,2,12,10,0)}] >>> prev = None >>> result = [] >>> for i in lisdic: ... if not prev: ... prev = i ... elif prev['end'] == i['begin'] - datetime.timedelta(seconds=1): ... prev['end'] = i['end'] ... else: ... result.append(prev) ... prev = i ... >>> >>> if prev: ... result.append(prev) ... >>> pprint.pprint(result) [{'begin': datetime.datetime(2015, 10, 2, 10, 0), 'end': datetime.datetime(2015, 10, 2, 12, 0)}, {'begin': datetime.datetime(2015, 10, 3, 10, 0), 'end': datetime.datetime(2015, 10, 3, 10, 30)}, {'begin': datetime.datetime(2015, 10, 3, 11, 0), 'end': datetime.datetime(2015, 10, 3, 11, 30)}, {'begin': datetime.datetime(2015, 10, 4, 12, 0), 'end': datetime.datetime(2015, 10, 2, 12, 10)}] 
+1
source share

All Articles