繁体   English   中英

Python IterTools分组

[英]Python itertools groupby

假设我有以下元组列表

[('FRG', 'MCO TPA PIE SRQ', 'WAVEY EMJAY J174 SWL CEBEE '), 
('                    ', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4'),
('                    ', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4')
('FRG2', 'MCO TPA PIE SRQ', 'WAVEY EMJAY J174 SWL CEBEE '), 
('                    ', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4')]

我如何将它们分组以最终获得命令,例如:

{'FRG': ['MCO TPA PIE SRQ', 'WAVEY EMJAY J174 SWL CEBEE ', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4'],
 'FRG2': ...}

就是说,我想将tuple[0]是一个单词的部分与(可能很多) tuple[0]为空的部分(仅包含空白)粘合在一起。
我用实验groupbytakewhileitertools ,但没有达成任何可行的解决方案。 理想情况下,解决方案包含其中之一(出于学习目的)。

并非我建议这样做,而是要使用itertools.groupby() ,您需要一个可以记住上次使用过的钥匙的钥匙功能。 像这样:

def keyfunc(item, keys=[None]):
    if item[0] != keys[-1] and not item[0].startswith(" "):
        keys.append(item[0])        
    return keys[-1] 

d = {k: [y for x in g for y in x[1:]] for k, g in groupby(lst, key=keyfunc)}

一个简单的for循环看起来更干净,并且不需要任何import

d, key = {}, None
for item in lst:
    if item[0] != key and not item[0].startswith(" "):
        key = item[0]
    d.setdefault(key, []).extend(item[1:])

使用collections.defaultdict子类的解决方案:

l = [('FRG', 'MCO TPA PIE SRQ', 'WAVEY EMJAY J174 SWL CEBEE '),
('                    ', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4'),
('                    ', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4'),
('FRG2', 'MCO TPA PIE SRQ', 'WAVEY EMJAY J174 SWL CEBEE '),
('                    ', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4')]

d = collections.defaultdict(list)
k = ''
for t in l:
    if t[0].strip():  # if the 1st value of a tuple is not empty
        k = t[0]      # capturing dict key
    if k:
        d[k].append(t[1])
        d[k].append(t[2])

print(dict(d))

输出:

{'FRG2': ['MCO TPA PIE SRQ', 'WAVEY EMJAY J174 SWL CEBEE ', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4'], 'FRG': ['MCO TPA PIE SRQ', 'WAVEY EMJAY J174 SWL CEBEE ', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4']}

函数groupbytakewhile不适用于此类问题。

groupby

groupby基于一组key功能。 这意味着您需要保留最后遇到的第一个非空白元组元素以使其工作。 这意味着您需要保持一些全局状态。 通过保持这种状态,该函数被称为“不纯函数”,而大多数(甚至所有)迭代工具都是纯函数。

from itertools import groupby, chain

d = [('FRG',                  'MCO TPA PIE SRQ', 'WAVEY EMJAY J174 SWL CEBEE '), 
     ('                    ', 'FMY RSW APF',     'WETRO DIW AR22 JORAY HILEY4'),
     ('                    ', 'FMY RSW APF',     'WETRO DIW AR22 JORAY HILEY4'),
     ('FRG2',                 'MCO TPA PIE SRQ', 'WAVEY EMJAY J174 SWL CEBEE '), 
     ('                    ', 'FMY RSW APF',     'WETRO DIW AR22 JORAY HILEY4')]

def keyfunc(item):
    first = item[0]
    if first.strip():
        keyfunc.state = first
    return keyfunc.state

{k: [item for idx, item in enumerate(chain.from_iterable(grp)) if idx%3 != 0] for k, grp in groupby(d, keyfunc)}

takewhile

takewhile需要提前确定何时停止yield值。 这意味着它将自动从迭代器弹出一个值,而不是每个组实际使用的值。 要实际应用它,您需要记住最后一个位置,然后每次创建一个新的迭代器。 还有一个问题是,您需要保持某种状态,因为您要使用一个不带空格的第一个元素的元素,然后取一个仅带空格的第一个元素的元素。

一种方法可能看起来像这样(但感觉不必要地复杂):

from itertools import takewhile, islice

def takegen(inp):
    idx = 0
    length = len(inp)
    while idx < length:
        first, *rest = inp[idx]
        rest = list(rest)
        for _, *lasts in takewhile(lambda x: not x[0].strip(), islice(inp, idx+1, None)):
            rest.extend(lasts)
        idx += len(rest) // 2
        yield first, rest

dict(takegen(d))

替代

您可以简单地创建自己的生成器来简化此过程。 这是takewhile方法的一种变体,但是它不需要外部状态, islicetakewhilegroupby或跟踪索引的方法:

def gen(inp):
    # Initial values
    last = None
    for first, *rest in inp:
        if last is None:       # first encountered item
            last = first
            l = list(rest)
        elif first.strip():    # when the first tuple item isn't all whitespaces
            # Yield the last "group"
            yield last, l
            # New values for the next "group"
            last = first
            l = list(rest)
        else:                  # when the first tuple item is all whitespaces
            l.extend(rest)
    # Yield the last group
    yield last, l

dict(gen(d))
# {'FRG2': ['MCO TPA PIE SRQ', 'WAVEY EMJAY J174 SWL CEBEE ', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4'], 
#  'FRG': ['MCO TPA PIE SRQ', 'WAVEY EMJAY J174 SWL CEBEE ', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4', 'FMY RSW APF', 'WETRO DIW AR22 JORAY HILEY4']}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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