【问题标题】:Can I count on order being preserved in a Python tuple?我可以指望在 Python 元组中保留订单吗?
【发布时间】:2011-05-18 14:43:48
【问题描述】:

我有一个日期时间列表,我想从中构建时间段。换句话说,将[t0, t1, ... tn] 变成[(t0,t1),(t1,t2),...,(tn-1, tn)]。我是这样做的:

# start by sorting list of datetimes
mdtimes.sort()
# construct tuples which represent possible start and end dates

# left edges
dtg0 = [x for x in mdtimes]
dtg0.pop()

# right edges
dtg1 = [x for x in mdtimes]
dtg1.reverse()
dtg1.pop()
dtg1.sort()

dtsegs = zip(dtg0,dtg1)

问题...

  1. 在我以这种方式创建任何 (tn-1,tn) 之后,我可以指望 tn-1
  2. 使用列表推导复制原始mdtimes 列表是否是一种好习惯?如果不是应该怎么做?
  3. 构造这些元组的目的是遍历它们并用tn-1tn 分割数据集。这是一个合理的方法吗?即

    datasegment = [x for x in bigdata if ( (x['datetime'] > tleft) and (x['datetime'] < tright))] 
    

谢谢

【问题讨论】:

  • 顺便说一句:(x['datetime'] &gt; tleft) and (x['datetime'] &lt; tright)(tleft &lt; x['datetime'] &lt; tright)
  • 你没有问的问题:给定x 已排序,x.reverse(); x.pop(); x.sort() 是个好主意吗?答案:;太可怕了; x.pop(0) 会做同样的事情,在任何情况下,几乎任何答案都比使用 pop() 方法更好。
  • 我最终选择了dtsegs = zip(mdtimes[:],mdtimes[1:])

标签: python list tuples


【解决方案1】:

listtuple 都是有序的。

dtg0, dtg1 = itertools.tee(mdtimes)
next(dtg0)
dtsegs = zip(dtg0, dtg1)

【讨论】:

  • 这是否比 Pawel 暗示的 dtsegs = zip(mdtimes[:],mdtimes[1:]) 建议有任何优势
  • @Pete:它不涉及创建 2 个临时列表。
【解决方案2】:
  1. 元组顺序是在您将值插入元组时。他们不会像我想你问的那样被分类。 zip 将再次保留您插入值的顺序。

  2. 这是一种可接受的方法,但我有 2 个替代建议:使用 copy 模块,或使用 dtg1 = mdtimes[:]

  3. 听起来很合理。

【讨论】:

    【解决方案3】:

    您可以使用zip 实现相同的效果:

    >>> l = ["t0", "t1", "t2", "t3", "t4", "t5", "t6"]
    >>> zip(l[::2], l[1::2])
    [('t0', 't1'), ('t2', 't3'), ('t4', 't5')]
    

    【讨论】:

    • 为了保持连续性,我使用了zip(l[:],l[1:])
    【解决方案4】:

    而不是:dtg0 = [x for x in mdtimes]dtg0 = mdtimes[:] 会这样做,因为您只需将一个列表复制到另一个列表中。注意:从 Python 3.3 开始,你可以直接说 newlist = oldlist.copy()

    至于顺序,zip的顺序定义明确,列表和元组都是有序集合,这里应该没问题。

    【讨论】:

    • list(mdtimes) 是另一种复制方式,恕我直言,这是其中最干净的。 list() 是一个构造函数,所以它总是创建一个新对象,即使它的参数已经是一个列表。
    • @Beni:这是成语和人们习惯的问题。有些人在心理上将[:] 视为复制列表。顺便说一句,有一个提议正在向列表对象添加一个copy 方法,所以上面变成了mdtimes.copy()。在此 Python 问题中对此进行了讨论:bugs.python.org/issue10516
    • 酷!你已经在 python 3.3 中登陆了 list.copy()list.clear()。我认为.copy() 是我最喜欢的新风格。
    • @BeniCherniavsky-Paskin:对,我可能应该更新这个答案:-)
    【解决方案5】:

    将 (x1, x2, x3, ...) 转换为 [(x1, x2), (x2, x3), ...] 称为成对组合,这种模式非常常见,以至于 itertools文档提供了一个配方:

    def pairwise(iterable):
        "s -> (s0,s1), (s1,s2), (s2, s3), ..."
        a, b = tee(iterable)
        next(b, None)
        return izip(a, b)
    
    for ta, tb in pairwise(mdtimes): 
        ....
    

    【讨论】:

      【解决方案6】:

      这是对“这是一种合理的方法吗?”问题的回答。 (似乎被所有人忽略了)。

      总结:您可能希望/需要将目光从mdtimes 中的成对事物转移到包含问题(分割bigdata)。

      详情:

      结果的期望用途表示为:

      datasegment = [x for x in bigdata if ( (x['datetime'] > tleft) and (x['datetime'] < tright))] 
      

      最好表达为:

      datasegment = [x for x in bigdata if tleft < x['datetime'] < tright] 
      

      请注意,就目前而言,它不包括时间戳完全等于边界点之一的任何情况,因此让我们将其更改为:

      datasegment = [x for x in bigdata if tleft <= x['datetime'] < tright]
      

      但这会出现在一个循环中:

      for tleft, tright in dtsegs:
          datasegment = [x for x in bigdata if tleft <= x['datetime'] < tright]
          do_something_with(datasegment)
      

      哎呀!这将花费与len(bigdata) * len(dtsegs) 成正比的时间......len(bigdata)len(dtsegs) 的可能值是多少?

      如果对bigdata进行排序,那么你想做的事情可以在与N成正比的时间内完成,其中N = len(bigdata)。如果bigdata尚未排序,则可以按与N * log(N)成比例的时间排序。

      您可能还想问另一个问题...

      还值得指出的是,bigdata 中时间戳 = max(mdtimes) 的任何项目都不会包含在任何数据段中……这是故意的吗?

      【讨论】:

      • 感谢 John... 里程有所不同,但 bigdata 大约有 10^6 条记录,并且大约有 5-10 个有用段,每个段中约有 10^5 条记录。 bigdata 本身没有排序,但它是从按字母顺序排列的文件序列中读取的,这些文件将日期作为名称的一部分,因此部分按日期时间排序。是的,如果某些数据不属于其中一个部分,则故意遗漏它。到目前为止的时间瓶颈是读取文本文件(每次分析 500MB+)、创建日期时间和压缩选定的数据列。
      【解决方案7】:

      我不是专家,但是您不是通过复制列表然后从两个列表中提取的对的新列表将内存需求翻了两番吗?为什么不直接执行以下操作:

      dtsegs = [(dtg0[i], dtg0[i+1]) for i in range(len(dtg0)-1)]
      

      但不知道这有多“Pythonic”。

      编辑:实际上,看看你需要用这个元组列表做什么,你可以直接在那个级别做这个 [i] 和 [i+1] 的东西,甚至根本不创建这个新结构。不过,我不知道你要处理多少个约会——如果是一个小数字,我想这并不重要。

      对于它的价值,这里的其他几个回答者似乎误解了你的问题,虽然我不能评论他们的帖子,因为我还没有足够的声誉 :) Ignacio Vazquez-Abrams 的解决方案似乎是最好的对我来说,虽然他的“下一个(dtg0)”应该是“下一个(dtg1)”(?)

      【讨论】:

      • 我个人宁愿有一个单独的结构和日期段,以使后续代码更容易理解。它还允许我查看片段以确保一切正常。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-08
      • 2011-11-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多