【问题标题】:List slicing with dynamic index on [:index]在 [:index] 上使用动态索引进行列表切片
【发布时间】:2015-07-25 03:08:31
【问题描述】:

我需要使用负动态索引 ([:-index]) 对列表进行切片。这很容易,直到我意识到如果我的动态索引的值为 0,则不返回任何项目,而不是返回整个列表。如何以当索引为 0 时返回整个字符串的方式实现这一点? 我的代码很长很复杂,但基本上这个例子说明了问题:

    arr='test text'
    index=2
    print arr[:-index]
    >>'test te'    #Entire string minus 2 from the right
    index=1
    print arr[:-index]
    >>'test tex'    #Entire string minus 1 from the right
    index=0
    print arr[:-index]
    >>''           #I would like entire string minus 0 from the right

注意:我使用的是 Python 2.7。

【问题讨论】:

  • 这行可能是错字吗?: >>'test te' #整个字符串从右边减去 1 在我看来与 index=2 的行相同,我感觉好像它应该显示'test tex'
  • 是的,我修正了错字

标签: python list slice


【解决方案1】:

这有点脱离了切片符号的简洁性,但你可以这样做

>>> arr[: len(arr) - 2]
'test te'
>>> arr[: len(arr) - 1]
'test tex'
>>> arr[: len(arr) - 0]
'test text'

【讨论】:

    【解决方案2】:

    您可以使用None 而不是0 来获取完整的切片:

    >>> arr = [1, 2, 3]
    >>> index = 1
    >>> arr[:-index if index else None]
    [1, 2]
    >>> index = 0
    >>> arr[:-index if index else None]
    [1, 2, 3]
    

    我的测试:

    import timeit
    
    def jonrsharpe(seq, index):
        return seq[:-index if index else None]
    
    def Cyber(seq, index):
        return seq[:len(arr) - index]
    
    def shashank(seq, index):
        return seq[:-index or None]
    
    if __name__ == '__main__':
        funcs = ('jonrsharpe', 'Cyber', 'shashank')
        arr = range(1000)
        setup = 'from __main__ import arr, {}'.format(', '.join(funcs))
        for func in funcs:
            print func
            for x in (0, 10, 100, 1000):
                print x,
                print timeit.timeit('{}(arr, {})'.format(func, x), setup=setup)
    

    和结果:

    jonrsharpe
    0 2.9769377505
    10 3.10071766781
    100 2.83629358793
    1000 0.252808797871
    Cyber
    0 3.11828875501
    10 3.10177615276
    100 2.82515282642
    1000 0.283648679403
    shashank
    0 2.99515364824
    10 3.11204965989
    100 2.85491723351
    1000 0.201558213116
    

    【讨论】:

    • 这似乎是迄今为止最好的答案。我测试了这个速度,比 Cyber​​ 的解决方案快 15 倍
    • @AndresLa 我的测试表明所有 3 个代码 sn-ps 的速度都差不多。对于非零索引,Jon 和我的速度比 Cyber​​ 的快一点点,但速度远不及 15 倍。
    • @AndresLa 我看到类似于 Shashank;三者的性能(使用timeit)非常一致(Cyber​​ 的速度可能慢了约 3%)。根据应用 dis,我希望 Shashank 的速度最快,但这并不能通过性能来证明。
    • @Shashank/@jonrsharpe,我更新了我的帖子以包含我用于测试的代码。我错过了什么吗?
    • @AndresLa 你错过了-,但这对结果没有影响!我有点疑惑;我已经包含了我的测试和结果,它们描绘了一幅截然不同的画面!
    【解决方案3】:

    另一个有趣的潜在解决方案。

    >>> arr = [1, 2, 3]
    >>> index = 0
    >>> arr[:-index or None]
    [1, 2, 3]
    >>> index = 1
    >>> arr[:-index or None]
    [1, 2]
    

    为了在字符串等不可变序列类型上获得更高的性能,您可以通过在切片操作之前检查索引的值,避免在索引为 0 的情况下完全切片序列。

    这里有三个函数要在性能方面进行测试:

    def shashank1(seq, index):
        return seq[:-index or None]
    
    def shashank2(seq, index):
        return index and seq[:-index] or seq
    
    def shashank3(seq, index):
        return seq[:-index] if index else seq
    

    在 index 为 0 的情况下,后两者应该快得多,但在其他情况下可能会更慢(或更快)。


    更新的基准代码: http://repl.it/oA5

    注意:结果很大程度上取决于 Python 实现。

    【讨论】:

      【解决方案4】:

      由于在选择最佳正确答案之前我无法入睡,因此除了@jonrsharpe 提供的脚本之外,我还使用两种不同的脚本测试了每个答案的性能。

      这是我使用profile比较三种不同解决方案性能的代码:

      import profile
      
      arr='test 123456789014'
      
      def jonrsharpe(index):
          global arr
          for c in range(1,100000,1):
              a=arr[:-index if index else None]
      
      def Cyber(index):
          global arr
          for c in range(1,100000,1):
              a=arr[:len(arr)-index]
      
      def shashank(index):
          global arr
          for c in range(1,100000,1):
              a=arr[:-index or None]
      
      def testf():
          for index in (0,3,6,9):
              jonrsharpe(index)
              Cyber(index)
              shashank(index)
      
      if __name__ == '__main__':
          profile.run("testf()")
      

      这是输出:

      ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      799992    1.629    0.000    1.629    0.000 :0(len)
         12    0.021    0.002    0.021    0.002 :0(range)
          1    0.006    0.006    0.006    0.006 :0(setprofile)
          1    0.000    0.000    4.390    4.390 <string>:1(<module>)
          0    0.000             0.000          profile:0(profiler)
          1    0.000    0.000    4.396    4.396 profile:0(testf())
          4    2.114    0.529    3.750    0.937 test.py:12(Cyber)
          4    0.307    0.077    0.313    0.078 test.py:19(shashank)
          1    0.000    0.000    4.390    4.390 test.py:26(testf)
          4    0.319    0.080    0.328    0.082 test.py:5(jonrsharpe)
      

      另一种方法:

      import time
      
      if __name__ == '__main__':
          arr = '01234567890123456789012345678901234567890123456789'#range(1000)
          for x in (0, 10, 20, 30,40,49):
              print 'index=',x
              start=time.clock()
              for count in range(1000000):
                  a=arr[:-x if x else None]
      
              print 'jonrsharpe=',round(time.clock()-start,4)
      
              start=time.clock()
              for count in range(1000000):
                  a=arr[:len(arr)-x]
              print 'Cyber     =',round(time.clock()-start,4)
      
              start=time.clock()
              for count in range(1000000):
                  a=arr[:-x or None]
              print 'shashank  =',round(time.clock()-start,4)
      

      输出:

      index= 0
      jonrsharpe= 0.4918
      Cyber     = 0.5341
      shashank  = 0.4269
      index= 10
      jonrsharpe= 0.4617
      Cyber     = 0.5334
      shashank  = 0.4105
      index= 20
      jonrsharpe= 0.4271
      Cyber     = 0.4562
      shashank  = 0.3493
      index= 30
      jonrsharpe= 0.4217
      Cyber     = 0.4548
      shashank  = 0.3264
      index= 40
      jonrsharpe= 0.4713
      Cyber     = 0.8488
      shashank  = 0.6458
      index= 49
      jonrsharpe= 0.6159
      Cyber     = 0.5663
      shashank  = 0.4312
      

      由于我将使用这行代码无数次,因此性能非常重要,@Shashank 的解决方案在大多数情况下都是赢家,即使只是一点点。

      【讨论】:

      • 请注意,我已将其设为社区 Wiki;我不会从中获得任何代表,任何人都可以对其进行编辑以添加其他方法的比较。
      猜你喜欢
      • 2019-03-17
      • 2020-02-27
      • 2015-06-14
      • 2018-12-11
      • 2019-11-14
      • 1970-01-01
      • 2018-11-22
      • 2021-11-20
      • 2018-03-12
      相关资源
      最近更新 更多