最优雅的方式来分离基于模式的列表(Python)

Fee*_*Man 6 python list

我有一个pandas列,列出了用户所做的连续日志操作,同时在每个整个日志记录会话中在移动应用程序中发布照片.假设单个列表如下所示:

my_list = [
      'action_a', 'action_b', 'action_c', 'action_z', 
      'action_j',
      'action_a','action_b', 
      'action_a', 'action_b', 'action_z']
Run Code Online (Sandbox Code Playgroud)

1)action_a - 照片上传的开始

2)action_z - 照片上传结束

3)其他actions_i - action_a和action_z之间可能发生的所有操作.

4)可能存在错误,例如'action_j',它们不在'action_a','action_z'之间,我们不应该将它们考虑在内

5)照片上传过程可能无法完成 - 因此可能存在'action_a','action_b'之类的路径.

GOAL =将my_list分隔为以'action_a'开头并以'action_z'结尾或在另一'action_a'之前结束的所有操作路径的子列表.所以结果应该是这样的:

['action_a', 'action_b', 'action_c', 'action_z'] 
['action_a','action_b']
['action_a', 'action_b', 'action_z']
Run Code Online (Sandbox Code Playgroud)

所以目前我正试图解决这个问题:首先我删除了所有的my_lists,其中'action_z'的数量大于'action_a'的数量或者没有'action_a'的数量.然后我做到了:

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] )
Run Code Online (Sandbox Code Playgroud)

好像它有效.有什么更好的方法?

Ale*_*lex 1

这个问题是基于意见的。但是,如果函数式适用于您的优雅概念,我建议使用某种分区算法,例如分组依据或分区依据。

这种高阶函数有不同的风格,但基本思想非常简单,您获取元素流或列表,并提供一个函数来告诉算法某个元素是否应被视为新列表开始的元素(我将其称为分区点)。我个人认为在数据结构中添加一层嵌套看起来更干净。即,您创建一个获取列表的函数并返回列表的列表。

# function that defines the start of a new sequence
def partition_begin(photo_action):
    return photo_action is 'action_a'

# function that defines the end of a new sequence
def partition_end(photo_action):
    return photo_action is 'action_z'

# get a list of elements and define a starting and stopping function
# and return a list of lists separated by start and stop.
def partition_by(elements, partition_separator, partition_terminator):
    partitioned_stream = []
    for element in elements:
        if partition_separator(element):
            # start a new list and append it to the stream.
            partitioned_stream.append([element])
            continue
        if partition_terminator(element):
            # add element to the last sequence, but start a new list. 
            partitioned_stream[-1].append(element)
            partitioned_stream.append([])
            continue
        # standard append to list.
        partitioned_stream[-1].append(element)
    return partitioned_stream


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

print partition_by(my_list, partition_begin, partition_end)

# [
#   ['action_a', 'action_b', 'action_c', 'action_z'],
#   ['action_j'],
#   ['action_a', 'action_b'],
#   ['action_a', 'action_b', 'action_z'],
#   []
# ]
Run Code Online (Sandbox Code Playgroud)

如果您有函数式编程语言,这会变得更有趣,因为这些类型的算法通常允许您将不同的函数嵌套到算法中。您可能已经注意到,此代码在末尾返回一个空列表,这可能看起来很奇怪,但您可以通过应用列表理解或简单地过滤空元素来摆脱它。

# remove empty elements from a list
non_empty = lambda x: len(x) > 0
filter(non_empty, partition_by(my_list, partition_begin, partition_end))
Run Code Online (Sandbox Code Playgroud)