如何通过true / false lambda函数使用itertools.groupby

假设我有以下字符串:

data = """
Pakistan[country]
Karachi
lahore
islamabad
UAE[country]
dubai
sharjah
India[country]
goa
chennai
"""

如何在此处使用itertools.groupby来决定(以国家/地区为键)及其对应的城市?我最接近的是

from itertools import groupby

filtered = (line for line in data.split("\n") if line)
for key,values in groupby(filtered,lambda line: line.endswith('[country]')):
    print(key)
    print(list(values))

但是,如何正确地将结果分组?我对其他可能的解决方案不感兴趣(我自己写了一个生成器函数),但想明确地使用/理解itertools.groupby


我的生成器函数看起来像

def grouper(string):
    collect,country,cities = False,None,list()

    filtered = (line for line in string.split("\n") if line)
    for line in filtered:
        if line.endswith('[country]') and not collect:
            country = line.replace("[country]","")
            collect = True
        elif line.endswith('[country]') and collect:
            yield {country: cities}
            country = line.replace("[country]","")
            cities = list()
        else:
            cities.append(line)

    if cities:
        yield {country: cities}

for dct in grouper(data):
    print(dct)


for dct in grouper(data):
    print(dct)

哪个产量

{'Pakistan': ['Karachi','lahore','islamabad']}
{'UAE': ['dubai','sharjah']}
{'India': ['goa','chennai']}
shangguan1 回答:如何通过true / false lambda函数使用itertools.groupby

我认为groupby是错误的工具。这是因为当键功能应用于它们时,它将收集所有具有相同结果的连续项。但是从问题描述中看,您似乎更希望在函数返回true时“拆分”列表。


但是,如果您真的想/必须使用groupby来做,那么(在概念上)将有两种方法:

一种可能的方法是从groupby结果中收集对。因此,您收集了一个给出true的值和以下返回False的值:

>>> filtered = (line for line in data.split("\n") if line)
>>> l = [list(g) for _,g in groupby(filtered,lambda line: line.endswith('[country]'))]
>>> d = {l[i*2][0].split('[')[0]: l[i*2+1] for i in range(len(l) // 2)}
>>> d
{'Pakistan': ['Karachi','lahore','islamabad'],'UAE': ['dubai','sharjah'],'India': ['goa','chennai']}

或者某种有状态的容器作为函数来记住“​​当前国家”是什么:

class KeepCountry:
    def __call__(self,item):
        if item.endswith('[country]'):
            self._last = item.split('[country]')[0]
        return self._last

>>> filtered = (line for line in data.split("\n") if line)
>>> {k: list(g)[1:] for k,KeepCountry())}
{'Pakistan': ['Karachi','chennai']}

这两个解决方案都假设有很多事情-万一您想使用其中的任何一个:

  • 遇到的第一个项目是一个国家/地区
  • 每个国家至少有一个关联的城市
  • 没有遇到一个以上的国家/地区名称

只要第三方包是可以接受的,那么您可以使用iteration_utilities(我的库),它为可迭代对象提供split功能:

>>> from iteration_utilities import Iterable

>>> (Iterable(data.split('\n'))
...    .filter(bool)  # Removes empty lines
...    # Split by countries while keeping them
...    .split(lambda l: l.endswith('[country]'),keep_after=True)[1:]  
...    # Convert to a tuple containing the country as first and the cities as second element
...    .map(lambda l: (l[0][:-9],l[1:]))  
...    .as_dict())
{'Pakistan': ['Karachi','chennai']}
,

不确定itertools,但为什么不呢?

from collections import defaultdict

data = """
Pakistan[country]
Karachi
lahore
islamabad
UAE[country]
dubai
sharjah
India[country]
goa
chennai
"""

dct = defaultdict(list)

country = ''

for x in data.split('\n')[1:-1]:
    if '[country]' in x:
        country = x.replace('[country]','')
    else:
        dct[country].append(x)

print(dct)

# {'Pakistan': ['Karachi','chennai']}
,

itertools.groupby()将返回国家和城市的交替序列。当它返回一个国家时,您将保存该国家。当它返回城市时,您可以在词典中添加带有保存国家的条目。

result = {}
for is_country,values in itertools.groupby(filtered,key = lambda line: line.endswith("[country]")):
    if is_country:
        country = next(values)
    else:
        result[country] = list(values)
本文链接:https://www.f2er.com/3135498.html

大家都在问