简体   繁体   中英

python deque/list filtering

I have a list of actions from a database. This is copied into a deque since I want to deal with it in order, popping stuff off the left as I go.

So I have something like actions = deque(actions) which is fine.

Each action item is a list from the psycopg module using the DictCursor. Each list has the item 'phase'.

So things go in phases. Some actions are in phase 'a', some in phase 'b', etc. Not the best way to store the data but that's what I was given.

So to make my life easier I want to split the deque into several deques by phase.

So if actions[0]['phase'] == 'a' then this goes in a list containing only items from phase a, and so on with, b, etc.

I could do this with a bunch of ifs and appending but that seems like a lot of effort. I think the answer might be filter(), but I'm not so sure how to use it.

Random stuff to note:

  • Each item is in order, the order needs preserving within each deque.
  • The phases are known and sequential. For example, if phase c doesn't exist, we know that phase d doesn't exist. There are a finite number of phases, something like 5 if I recall.

Clarification attempt:

I have a deque, actions. something like:

actions = [
    ['phase': 'a', 'something_else': 'x'], 
    ['phase': 'a', 'something_else': 'y'],
    ['phase': 'b', 'something_else': 'x']
]

Want to end up with (something like):

a = [
    ['phase': 'a', 'something_else': 'x'], 
    ['phase': 'a', 'something_else': 'y']
]
b = [
    ['phase': 'b', 'something_else': 'x']
]

With the minimal amount of code, and something that works for any number of phases/items in phases/etc.

First define a key function that returns the phase when given an action, eg

key = lambda action: action["phase"]

Now first sort by key -- this does not rearrange order more than necessary, ie order is conserved for each phase (it's " stable ") -- then use groupby from itertools like this:

from itertools import groupby

actions.sort(key=key)

results = []    
for phase, action_iterable in groupby(actions, key=key):
    action_list = list(action_iterable)
    action_list.reverse()
    results.append((phase, action_list)))

As you see I've reversed the lists. This is so you can just efficiently pop off the end of the lists instead of using popleft on a deque. If you prefer, turn them into a deque instead of reversing. Now use like this:

for phase, actions in results:
    while actions:
        action = actions.pop()
        # etc...

I think you want groupby from the itertools module.

http://docs.python.org/library/itertools.html#itertools.groupby

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM