Python 如何将itertools.groupby与真/假lambda函数一起使用

Python 如何将itertools.groupby与真/假lambda函数一起使用,python,group-by,Python,Group By,假设我有以下字符串: data = """ Pakistan[country] Karachi lahore islamabad UAE[country] dubai sharjah India[country] goa chennai """ 如何使用itertools.groupby这里有一个dict(以国家为键)及其对应的城市?我最接近的是 from itertools import groupby filtered = (line for line in data.split("\n

假设我有以下字符串:

data = """
Pakistan[country]
Karachi
lahore
islamabad
UAE[country]
dubai
sharjah
India[country]
goa
chennai
"""
如何使用
itertools.groupby
这里有一个dict(以国家为键)及其对应的城市?我最接近的是

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']}
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)

我认为这方面的
groupby
是错误的工具。这是因为它收集了所有连续项,这些项在对其应用键函数时具有相同的结果。然而,从问题描述来看,当函数返回true时,似乎更希望“分割”列表


但是,如果您真的想/必须使用
groupby
实现这一点,那么(概念上)有两种方法:

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

>>filtered=(数据中每行对应一行。如果为行,则拆分(“\n”))
>>>l=[groupby中ug的列表(g)(已过滤,lambda行:line.endswith(“[country]”))]
>>>d={l[i*2][0].split('[')[0]:l[i*2+1]表示范围(len(l)//2)内的i
>>>d
{‘巴基斯坦’:[‘卡拉奇’、‘拉合尔’、‘伊斯兰堡’],
“阿联酋”:[“迪拜”、“沙迦”],
‘印度’:[‘果阿’、‘钦奈’]}
或者某种有状态的容器,作为记住“当前国家”是什么的函数:

class KeepCountry:
定义呼叫(自身,项目):
如果项.endswith(“[国家]”):
self._last=item.split(“[国家]”)[0]
返回自我
>>>筛选=(数据中的行对应行。如果行为拆分(“\n”))
>>>{k:list(g)[1:]用于groupby(filtered,KeepCountry())中的k,g}
{‘巴基斯坦’:[‘卡拉奇’、‘拉合尔’、‘伊斯兰堡’],
“阿联酋”:[“迪拜”、“沙迦”],
‘印度’:[‘果阿’、‘钦奈’]}
这两种解决方案都假设了很多事情——以防您想要使用以下任何一种:

  • 遇到的第一个项目将是国家/地区
  • 每个国家至少有一个相关城市
  • 没有多次遇到国家/地区名称

如果可以接受第三方软件包,那么您可以使用(我的库),它为iterables提供了一个-函数:

>>从迭代\u实用程序导入Iterable
>>>(Iterable(data.split('\n'))
..过滤器(bool)#删除空行
…#由国家分割,同时保留它们
..拆分(lambda l:l.endswith(“[country]”),保留后面的值=True)[1:]
…#转换为一个元组,其中包含国家作为第一个元素,城市作为第二个元素
…映射(lambda l:(l[0][:-9],l[1:]))
…如_dict())
{‘巴基斯坦’:[‘卡拉奇’、‘拉合尔’、‘伊斯兰堡’],
“阿联酋”:[“迪拜”、“沙迦”],
‘印度’:[‘果阿’、‘钦奈’]}

不确定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', 'lahore', 'islamabad'], 'UAE': ['dubai', 'sharjah'], 'India': ['goa', 'chennai']}

最终的结果应该是什么?阿联酋不应该成为一个键吗?你真的想要一系列的字典,而不是一个键为Countries的字典吗?这两个词都是丑陋和光滑的同时——好极了!
是一个生成器,我把它改成了使用
下一个()
。谢谢你,这是(至少对我来说)最容易理解的解决方案。最后只需从字符串中替换
[country]