Python从另一个列表中创建列表中的元组

And*_*ius 4 python tuples list

假设我有这样的数据:

data = [1, 2, 3, -4, -5, 3, 2, 4, -2, 5, 6, -5, -1, 1]
Run Code Online (Sandbox Code Playgroud)

我需要它由元组分组在另一个列表中.一个元组由两个列表组成.一个是正​​数,另一个是负数.应该通过检查它是什么类型的数字来创建元组.最后的负数(我的意思是连续的负数之间没有正数)意味着,其他数字必须进入另一个元组,当它找到另一个最后的负数时,它应该创建另一个元组.

因此规则是这样的:所有找到的数字都被添加到第一个元组中,当它找到负数时,它仍然将它添加到该元组,直到它找到正数(这意味着必须创建新的元组).

我认为展示比解释更容易.解析后data,列表应如下所示:

l = [([1, 2, 3], [-4, -5]), ([3, 2, 4], [-2]), ([5, 6], [-5, -1]), ([1], [])]
Run Code Online (Sandbox Code Playgroud)

我创建了一个解决方案,但我想知道它是否非常理想.也许有可能写一个更优雅的(我想知道性能,有没有更好的方法来编写这样的解析器具有最佳性能:))?

def neighborhood(iterable):
    iterator = iter(iterable)
    prev = None
    item = iterator.next()  # throws StopIteration if empty.
    for next in iterator:
        yield (prev,item,next)
        prev = item
        item = next
    yield (prev,item,None)

l = []    
pos = []
neg = []
for prev, item, next in neighborhood(data):
    if item > 0:
        pos.append(item)
        if not next:
            l.append((pos, neg))
    else:
        neg.append(item)
        if next > 0:
            l.append((pos, neg))
            pos = []
            neg = []
        elif not next:
            l.append((pos, neg))

print l
Run Code Online (Sandbox Code Playgroud)

PS if not next部分我认为主要检查后只能使用一次.

Ale*_*ley 8

我首先使用itertools.groupby包含正/负列表的连续元组列表,然后分组成连续对.这仍然可以通过利用生成器在列表中一次完成:

from itertools import groupby, zip_longest

x = (list(v) for k,v in groupby(data, lambda x: x < 0))
l = list(zip_longest(x, x, fillvalue=[]))
Run Code Online (Sandbox Code Playgroud)

这给出l了:

[([1, 2, 3], [-4, -5]), ([3, 2, 4], [-2]), ([5, 6], [-5, -1]), ([1], [])]
Run Code Online (Sandbox Code Playgroud)

关于上面代码的几点说明:

  • 将初始分组转换为正/负值,groupby这应该是合理的性能(它是编译代码).

  • 用于分组成对的zipping-a-generator方法是Python中相当常见的习惯用法.它保证可以工作,因为zip保证比从左到右消耗迭代.

  • 在Python 2中,使用izip_longest.