编辑:这是基于原始问题,假设数据将位于单个列表中,而不是多个输入列表中。对问题的编辑清楚地表明情况并非如此,因此我建议您遵循Janne Karila 的解决方案。
假设您知道有多少不同的值,这是一个很好的解决方案,使用itertools
' grouper()
recipe:
import itertools
def grouper(n, iterable, fillvalue=None):
args = [iter(iterable)] * n
return itertools.zip_longest(fillvalue=fillvalue, *args)
data = ["date", "1a", "2a", "3a", "1b", "2b", "3b", "1c", "2c", "3c"]
first = data.pop(0)
print([list(zip(itertools.repeat(first), items)) for items in zip(*grouper(3, data))])
给我们:
[
[('date', '1a'), ('date', '1b'), ('date', '1c')],
[('date', '2a'), ('date', '2b'), ('date', '2c')],
[('date', '3a'), ('date', '3b'), ('date', '3c')]
]
请注意,None
如果没有足够的值,这将用 s 填充列表。
当然,如果只想循环遍历它,例如不显示它,您可以使用生成器推导而不是列表推导。例如:
(zip(itertools.repeat(first), items) for items in zip(*grouper(3, data)))
请注意,我使用的是 Python 3.x,所以在 2.x 下,无论我在哪里使用zip()
你可能想要itertools.izip()
的,并且itertools.zip_longest()
变成itertools.izip_longest()
.
请注意,这样做的更好方法 - 假设您知道什么定义了应该在第一个列表中的值,应该在第二个列表中的值,等等......
import itertools
import operator
data = ["date", "1a", "2a", "3a", "1b", "2b", "3b", "1c", "2c", "3c"]
first = data.pop(0)
print([list(zip(itertools.repeat(first), items)) for _, items in itertools.groupby(sorted(data), operator.itemgetter(0))])
产生:
[
[('date', '1a'), ('date', '1b'), ('date', '1c')],
[('date', '2a'), ('date', '2b'), ('date', '2c')],
[('date', '3a'), ('date', '3b'), ('date', '3c')]
]
自然,这仅适用于给定的示例,假设您的真实数据不同,您将需要更改operator.itemgetter(0)
为定义您的项目应分组到哪个列表的函数。
请注意,我们可能值得封装我们的前缀工作:
def prefix(iterable, prefix):
"""Returns every element of an iterable prefixed with a given value."""
#prefix("ABCDEFG", "x") --> ("x", "A"), ("x", "B"), ("x", "C"), ("x", "D"), ...
return zip(itertools.repeat(prefix), iterable)
然后我们有简单的:
(prefix(items, first) for items in zip(*grouper(3, data)))
和
(prefix(items, first) for _, items in itertools.groupby(sorted(data), operator.itemgetter(0)))
哪个更具可读性。