通过遍历可迭代来对谓词进行分区

时间:2016-08-29 00:26:20

标签: python

假设我有一个类似的序列:

seq = (1, 1, 1, 1, 4, 6, 8, 4, 3, 3, 3,)

一些任意数量的1,后跟一些任意数量的偶​​数,然后是3s。如果我试着把它分开:

it = iter(seq)
ones = list(takewhile(lambda x: x == 1, it))
evens = list(takewhile(lambda x: x%2 == 0, it))
threes = list(takewhile(lambda x: x == 3, it))

这个几乎可以解决...除了我错过了第一个偶数和前三个,因为它已经被takewhile用完了。有没有办法通过向前走迭代器,谓词谓词来进行这种分区?

3 个答案:

答案 0 :(得分:1)

你可以这样做:

def multi_takewhile(predicates, iterable):
    ipredicates = iter(predicates)
    predicate = next(ipredicates)

    last_chunk = []

    for element in iterable:
        while not predicate(element):
            yield last_chunk

            last_chunk = []

            try:
                predicate = next(ipredicates)
            except StopIteration:
                break

        last_chunk.append(element)

但是,如果你的谓词用完了,它仍会遇到消耗最后一个元素的问题。您可以修改函数以返回另一个列表中的最后一个元素,或者创建自己的可迭代包装器,以跟踪最后一个元素。

另一种更itertools方法可能是groupby

import itertools

class Grouper(object):
    def __init__(self, predicates):
        self.predicates = iter(predicates)
        self.predicate = next(self.predicates)
        self.key = 0

    def __call__(self, element):
        if not self.predicate(element):
            self.key += 1
            self.predicate = next(self.predicates)

        return self.key

def multi_takewhile(predicates, iterable):
    for _, group in itertools.groupby(iterable, Grouper(predicates)):
        yield tuple(group)

seq = [1, 1, 1, 1, 4, 6, 8, 4, 3, 3, 3]
ones, evens, threes = multi_takewhile([(lambda x: x == 1), (lambda x: x%2 == 0), (lambda x: x == 3)], seq)

答案 1 :(得分:1)

groupby可以在这里使用精心设计的关键函数来处理任意关键函数:

def f1(x): return x == 1
def f2(x): return x%2 == 0
def f3(x): return x == 3
fs = [f1, f2, f3]

def keyfunc(x): return next((f for f in fs if f(x)), None)

for k, vals in itertools.groupby(data, keyfunc):
    assert k in {f1, f2, f3, None}
    print k, vals

这显然有时会创建重复的分区,例如[1, 1, 3, 1, 3]

答案 2 :(得分:0)

您的示例可由0.704处理:

groupby