4

我有一组从数据库返回的记录,格式如下:

data = [
    ["date", "value1a", "value2a", "value3a", ...],
    ["date", "value1b", "value2b", "value3b", ...]
]

我想把那组行变成一个列表,比如

[
    [("date", "value1a"), ("date", "value1b"), ... ],
    [("date", "value2a"), ("date", "value2b"), ... ]
]

我知道zip()会做这种事情,但我不清楚如何将日期输入每条记录(并使它们成为元组)。从数据库返回的行的长度并不总是相同的,但我会知道每次调用的预期长度。

4

4 回答 4

4
data = [["date_a", "1a", "2a", "3a"], 
        ["date_b", "1b", "2b", "3b"]]

print zip(*(zip(itertools.repeat(ls[0]), ls[1:]) for ls in data))

[(('date_a', '1a'), ('date_b', '1b')),
 (('date_a', '2a'), ('date_b', '2b')),
 (('date_a', '3a'), ('date_b', '3b'))]

有关一些有用的变化,请参阅注释。

于 2012-05-21T19:18:49.220 回答
2

编辑:这是基于原始问题,假设数据将位于单个列表中,而不是多个输入列表中。对问题的编辑清楚地表明情况并非如此,因此我建议您遵循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)))

哪个更具可读性。

于 2012-05-21T16:15:19.313 回答
2

对第一个元素使用 itertools 重复:

zip(itertools.repeat(ls[0]), ls[1:])
于 2012-05-21T15:31:34.503 回答
0

这也可以通过简单的列表理解技术来实现

data = [    ["date1", "value1a1", "value2a1", "value3a1"],
            ["date2", "value1b2", "value2b2", "value3b2"]
       ]
result = map(list, zip(*[[(x[0], x[i]) for x in data] for i in range(1,len(x))]))

[
  [('date1', 'value1a1'), ('date1', 'value2a1'), ('date1', 'value3a1')],
  [('date2', 'value1b2'), ('date2', 'value2b2'), ('date2', 'value3b2')]
]
于 2013-02-25T07:32:06.227 回答