Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Most elegant way to separate list based on pattern (Python)

Tags:

python

list

I have a pandas column of lists of consecutive log actions that users do, while posting a photo in mobile app in each whole logging session. Suppose the single list looks like:

my_list = [
      'action_a', 'action_b', 'action_c', 'action_z', 
      'action_j',
      'action_a','action_b', 
      'action_a', 'action_b', 'action_z']

1) action_a - the start of photo upload

2) action_z - the end of photo upload

3) other actions_i - all the actions that can occur between action_a and action_z.

4) there may be errors, like 'action_j', that appear not between 'action_a', 'action_z' and we shouldn't take them into account

5) the process of photo upload may not be completed - so there may be path like 'action_a','action_b'.

The GOAL = separate my_list into sublists of all action paths that starts with 'action_a' and ends with 'action_z' or ends before another 'action_a'. So the result should be like that:

['action_a', 'action_b', 'action_c', 'action_z'] 
['action_a','action_b']
['action_a', 'action_b', 'action_z']

So currently I am trying to solve it like that: firstly I've deleted all my_lists, where the number of 'action_z' is greater than the number of 'action_a' or where there is no 'action_a'. Then I did that:

indices_a = [i for i, x in enumerate(my_list) if x == "action_a"]
indices_z = [i for i, x in enumerate(my_list) if x == "action_z"]

if(len(indices_z)<1):
    for i_a,x_a in enumerate(indices_a):
        if (i_a+1 != len(indices_a)):
            indices_z.append(indices_a[i_a+1]-1) 
        else: indices_z.append(len(my_list)-1) 
else:       
    for i_a,x_a in enumerate(indices_a):
        if (i_a+1 != len(indices_a)):
            if (indices_z[i_a] > indices_a[i_a+1] ):
                indices_z.insert(i_a, indices_a[i_a+1]-1)
        else:  indices_z.append(len(my_list)-1) 

res=[]
for i,j in zip(indices_a, indices_z):
    res.append(my_list[i:j+1] )

Seems like it works. What is the better way?

like image 348
Feels Good Man Avatar asked Jun 17 '17 11:06

Feels Good Man


1 Answers

I've tried to simplify things a little and came up with this logic:

result = []
curr_list = None

for item in my_list:
    if item == 'action_a':
        if curr_list is not None:
            # Only append is there is content
            result.append(curr_list)
        # Create a new list
        curr_list = []

    try:
        # Try to append the current item
        curr_list.append(item)

        if item == 'action_z':
            # Close the current list but don't initialize 
            # a new one until we encounter action_a
            result.append(curr_list)
            curr_list = None
    except AttributeError:
        # This means we haven't encountered action_a yet
        # Just ignore and move on
        pass

if curr_list is not None:
    # Append an "open" list if there is one
    result.append(curr_list)

for item in result:
    print(item)

Result:

['action_a', 'action_b', 'action_c', 'action_z']
['action_a', 'action_b']
['action_a', 'action_b', 'action_z']
like image 192
DocZerø Avatar answered Sep 20 '22 11:09

DocZerø