How to find the first index of any of a set of characters in a string

后端 未结 4 1460
梦毁少年i
梦毁少年i 2020-12-20 11:44

I\'d like to find the index of the first occurrence of any “special” character in a string, like so:

>>> \"Hello world!\".index([\' \', \'!\'])
5
         


        
4条回答
  •  误落风尘
    2020-12-20 12:20

    Use a gen-exp and the find method.

    >>> a = [' ', '!']
    >>> s = "Hello World!"
    >>> min(s.find(i) for i in a)
    5
    

    To remove -1s if they occur, you can have a filter within the list comp

    >>> a = [' ', '!','$']
    >>> s = "Hello World!"
    >>> min(s.find(i) for i in a if i in s)
    5
    

    or you can substitute None

    >>> min(s.find(i) if i in s else None for i in a)
    5
    

    Adding the timeit results

    $ python -m timeit "a = [' ', '\!'];s = 'Hello World\!';min(s.find(i) for i in a if i in s)"
    1000000 loops, best of 3: 0.902 usec per loop
    $ python -m timeit "a = [' ', '\!'];s = 'Hello World\!';next((i for i, ch  in enumerate(s) if ch in a),None)"
    1000000 loops, best of 3: 1.25 usec per loop
    $ python -m timeit "a = [' ', '\!'];s = 'Hello World\!';min(map(lambda x: (s.index(x) if (x in s) else len(s)), a))"
    1000000 loops, best of 3: 1.12 usec per loop
    

    In your Example case, Padraic's beautiful solution is a little slow. However in large test cases, It is definitely a winner. (It's a little surprising that alfasin's "Not as optimized" is also faster here)

    Added the implementation details

    >>> def take1(s,a):
    ...     min(s.find(i) for i in a if i in s)
    ... 
    >>> import dis
    >>> dis.dis(take1)
      2           0 LOAD_GLOBAL              0 (min)
                  3 LOAD_CLOSURE             0 (s)
                  6 BUILD_TUPLE              1
                  9 LOAD_CONST               1 ( at 0x7fa622e961b0, file "", line 2>)
                 12 MAKE_CLOSURE             0
                 15 LOAD_FAST                1 (a)
                 18 GET_ITER            
                 19 CALL_FUNCTION            1
                 22 CALL_FUNCTION            1
                 25 POP_TOP             
                 26 LOAD_CONST               0 (None)
                 29 RETURN_VALUE        
    >>> def take2(s,a):
    ...     next((i for i, ch  in enumerate(s) if ch in a),None)
    ... 
    >>> dis.dis(take2)
      2           0 LOAD_GLOBAL              0 (next)
                  3 LOAD_CLOSURE             0 (a)
                  6 BUILD_TUPLE              1
                  9 LOAD_CONST               1 ( at 0x7fa622e96e30, file "", line 2>)
                 12 MAKE_CLOSURE             0
                 15 LOAD_GLOBAL              1 (enumerate)
                 18 LOAD_FAST                0 (s)
                 21 CALL_FUNCTION            1
                 24 GET_ITER            
                 25 CALL_FUNCTION            1
                 28 LOAD_CONST               0 (None)
                 31 CALL_FUNCTION            2
                 34 POP_TOP             
                 35 LOAD_CONST               0 (None)
                 38 RETURN_VALUE        
    >>> def take3(s,a):
    ...     min(map(lambda x: (s.index(x) if (x in s) else len(s)), a))
    ... 
    >>> dis.dis(take3)
      2           0 LOAD_GLOBAL              0 (min)
                  3 LOAD_GLOBAL              1 (map)
                  6 LOAD_CLOSURE             0 (s)
                  9 BUILD_TUPLE              1
                 12 LOAD_CONST               1 ( at 0x7fa622e44eb0, file "", line 2>)
                 15 MAKE_CLOSURE             0
                 18 LOAD_FAST                1 (a)
                 21 CALL_FUNCTION            2
                 24 CALL_FUNCTION            1
                 27 POP_TOP             
                 28 LOAD_CONST               0 (None)
                 31 RETURN_VALUE        
    

    As you can clearly see in Padraic's case the loading of the global functions next and enumerate are the ones which are killing the time along with None at the end. In alfasin's solution the primary slowing down is the lambda function.

提交回复
热议问题