让我们说,我有以下元组列表
[('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')]
如何将这些组合成最终的dict,如:
{'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]
为空的(可能很多)以下部分粘合在一起(仅包含空格)。
我正在试验groupby
中的takewhile
和itertools
,但尚未找到任何可行的解决方案。理想情况下,解决方案包含其中一个(出于学习目的,即)。
答案 0 :(得分:3)
不是我推荐它,而是为此使用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
s:
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:])
答案 1 :(得分:2)
使用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']}
答案 2 :(得分:1)
函数groupby
和takewhile
不适合此类问题。
groupby
key
函数的 groupby
个组。这意味着您需要保留最后遇到的第一个非空白元组元素才能使其正常工作。这意味着你要保持一些全球状态。通过保持这种状态,函数被称为"unpure",而大多数(甚至所有)itertools都是纯函数。
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
方法的变体,但它不需要外部状态,islice
,takewhile
,groupby
或者跟踪索引:
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']}