Reputation: 27
I've spent about 6 hours on this, so I feel justified in asking a question. :)
My problem
list1 = [
{extension: 1000, id: 1}
{extension: 1001, id: 1}
{extension: 1000, id: 2}
]
list2 = [
{Stationextension: 1000, id: 1, name: bob}
{Stationextension: 1001, id: 1, name: sal}
{Stationextension: 1000, id: 2, name: cindy}
]
My pseudo code is this.
Delete list2[d] (whole dictionary from list of dicts) where list1[d]['extension'] == list2[d]['Stationextension'] AND id == id.
List 1 is much smaller and has to stay unchanged relative to list 2 if that matters.
Using Python3.3, I have something like
[x for x in list2 if (list1[x]['stationExtension'] == x.get('extension'))]
Thanks !
Upvotes: 0
Views: 118
Reputation: 365697
The right way to do this is to use the right data structures for the job. Instead of figuring out how to search a list based on a key, use a dict with that key. For example:
dict1 = {x['extension']: x for x in list1}
Now, you can just write this:
[x for x in list2 if x['stationExtension'] in dict1}
Elsewhere in your question, it seems like you wanted to use the extension and the id, not just the extension, as a key. But that's just as easy; you can use a tuple:
dict1 = {(x['extension'], x['id']): x for x in list1}
[x for x in list2 if (x['stationExtension'], x['id']) in dict1}
If you want to know why your code doesn't work… let's look at it:
[x for x in list2 if (list1[x]['stationExtension'] == x.get('extension'))]
list1[x]
is trying to use the dict as an index, which doesn't mean anything. What you really want to say is "if, for any element of list1, element['stationExtension'] == x.get('extension')
". And you can translate that almost directly to Python:
[x for x in list2
if any(element['stationExtension'] == x.get('extension')
for element in list1)]
And of course to add the and element['id'] == x['id']
onto the end of the condition.
But again, the dict
is a better solution. Besides being a whole lot simpler to read and write, it's also more efficient. Searching for any matches in a list requires checking each element in the list; searching for any matches in a dict just requires hashing the key and looking it up in a hash table. So, this way takes O(NM) time (where N is the length of list1, and M is the length of list2), while the dict only takes O(M) time.
Upvotes: 1
Reputation: 4675
Python 2.7:
removelist=[]
for i,x in enumerate(list2):
if x['Stationextension'] == list1[i]['extension'] and x['id'] == list1[i]['id']:
removelist+=[i]
And once you've decided what to delete:
for x in removelist:
del list1[x]
Upvotes: 0
Reputation: 110261
Assuming that you want to delete items from list2 with the same value in "Stationextention" on list2 and "extention" on list 1 - You better first create a set with all values to delete - that will avoid a linear search at each time you want to check if an entry will stay:
indexes = set(item["extention"] for item in list1)
And - one thing that happens is that you usually can't iterate over a list and delete items from it while at it:
new_list2 = []
for item in list2:
if item["Stationextention"] not in indexes:
new_list2.append(item)
list2 = new_list2
Upvotes: 0
Reputation: 1381
list2 = [x for x in list2 if {'extension': x['Stationextension'], 'id': x['id']} not in list1]
or, if you know that the lengths and indexes will match:
list2 = [y for x,y in itertools.izip(list1, list2) if x['extension'] == y['StationExtension'] and x['id'] == y['id']]
Upvotes: 1