分入时隙 - 有没有比使用list comp更好的方法?

时间:2010-06-10 22:46:04

标签: python

我有一个事件数据集(特定的推文),我试图进行分区/离散化。到目前为止,以下代码似乎工作正常(假设有100个分箱):

HOUR = timedelta(hours=1)
start = datetime.datetime(2009,01,01)
z = [dt + x*HOUR for x in xrange(1, 100)]

然而,我在python docs遇到了这个命运的路线'这使得使用zip(*[iter(s)]*n)'将数据系列聚类成n长度组成为可能。 zip惯用语确实有用 - 但我无法理解(例如*运算符是什么?)。我怎么能用来使我的代码更漂亮?我猜这意味着我应该制作一个生成器/可迭代的时间yields在一个小时的毕业时间?

2 个答案:

答案 0 :(得分:5)

文档中的表达式如下所示:

zip(*[iter(s)]*n)

这相当于:

it = iter(s)
zip(*[it, it, ..., it]) # n times

[...]*n重复列表n次,这会产生一个包含n对同一迭代器的引用的列表。

这又等于:

it = iter(s)
zip(it, it, ..., it)    # turning a list into positional parameters

列表前的*将列表元素转换为函数调用的位置参数。

现在,当调用zip时,它从左到右开始调用迭代器以获取应该组合在一起的元素。由于所有参数都引用相同的迭代器,因此产生初始序列的第一个n元素。然后,对结果列表中的第二个组继续该过程,依此类推。

结果与您构建这样的列表(从左到右评估)相同:

it = iter(s)
[(it.next(), it.next(), ..., it.next()), (it.next(), it.next(), ..., it.next()),  ...]

答案 1 :(得分:5)

我将尝试用更简单的例子解释zip(*[iter(s)]*n)

假设你有列表s = [1, 2, 3, 4, 5, 6]

iter(s)会为您提供一个listiterator对象,每当您要求元素时,该对​​象将从s生成下一个数字。

[iter(s)] * n为其提供了 n iter(s)的列表,例如[iter(s)] * 2 = [<listiterator object>, <listiterator object>] - 这里的关键是这些是对相同迭代器对象的2个引用,而不是2个不同的迭代器对象。

zip接受许多序列并返回一个元组列表,其中每个元组包含来自每个序列的 ith 元素。例如zip([1,2], [3,4], [5,6]) = [(1, 3, 5), (2, 4, 6)]其中(1, 3, 5)是传递给zip(2, 4, 6)的参数的第一个元素,是传递给zip的参数中的第二个元素。

*前面的*[iter(s)]*n会将[iter(s)]*n从列表转换为传递给zip的多个参数。因此,如果n为2,我们会得到zip(<listiterator object>, <listiterator object>)

zip将从其每个参数中请求下一个元素,但因为它们都是对同一个迭代器的引用,这将导致(1, 2),它会再次执行相同的操作,从而导致(3, 4)并再次产生(5, 6),然后没有更多的元素,所以它停止。因此结果为[(1, 2), (3, 4), (5, 6)]。这是将数据系列聚类成n长组,如上所述。