按元组分隔符拆分列表

时间:2017-09-30 06:08:59

标签: python list tuples separator

我有清单:

$(document).ready(function() {
    $('.bxslider-two').bxSlider();
});

$('a[href="#profile"]').one('shown.bs.tab', function(e) {
    $('.bxslider').bxSlider();
});

我希望拆分列表到分隔符print (L) [('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), ('.', 'ZZ'), ('You', 'WW'), ('are', 'XX'), ('cool', 'YY'), ('.', 'ZZ')] 的子列表:

('.', 'ZZ')

我对另一种可能的解决方案感兴趣,性能很重要。

7 个答案:

答案 0 :(得分:4)

vanilla for循环应该比groupby更快。

L2 = []
for i in L[::-1]:
     if i == ('.','ZZ'):
         L2.append([])

     L2[-1].append(i)

L2 = [x[::-1] for x in L2[::-1]]

一个小小的调整(可能/可能没有提高性能 - 但更节省内存)涉及使用reversed

L2 = []
sep = ('.','ZZ')
for i in reversed(L):
     if i == sep:
         L2.append([])

     L2[-1].append(i)

L2 = [x[::-1] for x in reversed(L2)]

另一项改进是使用另一个引用减少L[-1]引用:

cache = []
L2 = cache
sep = ('.','ZZ')
for i in reversed(L):
     if i == sep:
         cache = []
         L2.append(cache)

     cache.append(i)

L2 = [x[::-1] for x in reversed(L2)]

效果

<强>小

len(L)
8
100000 loops, best of 3: 5.11 µs per loop   # groupby
100000 loops, best of 3: 3.54 µs per loop   # loop

<强>大

len(L)
800000
1 loop, best of 3: 435 ms per loop    # groupby
1 loop, best of 3: 310 ms per loop    # PM 2Ring's groupby
1 loop, best of 3: 250 ms per loop    # loop
1 loop, best of 3: 235 ms per loop    # loop w/ reverse

答案 1 :(得分:4)

你的代码看起来不错,但你可以通过摆脱lambda来加快速度,例如

groupby(L, sep.__eq__)

不仅代码更短,还节省了创建lambda函数的开销,以及相对较慢的Python函数调用。

您还可以在循环外部构建[sep],这可能会节省几微秒。 ;)

from  itertools import groupby

L = [('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), ('.', 'ZZ'), 
    ('You', 'WW'), ('are', 'XX'), ('cool', 'YY'), ('.', 'ZZ')]

sep = ('.','ZZ')
seplist = [sep]
new_L = [list(g) + seplist for k, g in groupby(L, sep.__eq__) if not k] 
for row in new_L:
    print(row)    

<强>输出

[('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), ('.', 'ZZ')]
[('You', 'WW'), ('are', 'XX'), ('cool', 'YY'), ('.', 'ZZ')]

答案 2 :(得分:4)

for循环方法会更快,这只需要一遍:

>>> def juan(L, sep):
...     L2 = []
...     sub = []
...     for x in L:
...         sub.append(x)
...         if x == sep:
...             L2.append(sub)
...             sub = []
...     if sub:
...         L2.append(sub)
...     return L2
...
>>> juan(L, sep)
[[('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), ('.', 'ZZ')], [('You', 'WW'), ('are', 'XX'), ('cool', 'YY'), ('.', 'ZZ')]]

一些比较:

>>> def jezrael(L, sub):
...     return [list(g) + [sep] for k, g in groupby(L, lambda x: x==sep) if not k]
...
>>> def coldspeed(L, sep):
...     L2 = []
...     for i in reversed(L):
...         if i == sep:
...             L2.append([])
...         L2[-1].append(i)
...     return [x[::-1] for x in reversed(L2)]
...
>>> def pm2ring(L, sep):
...     seplist = [sep]
...     return [list(g) + seplist for k, g in groupby(L, sep.__eq__) if not k]
...
>>> setup = "from __main__ import L, sep, juan, coldspeed, pm2ring, jezrael"

编辑:更多时间

>>> def buzzycoder(L, sep):
...     a = []
...     length = len(L)
...     start = 0
...     end = L.index(sep)
...     if start < length: a.append(L[start:end+1])
...     start = end + 1
...     while start < length:
...         end = L.index(sep, start) + 1
...         a.append(L[start:end])
...         start = end
...     return a
...

>>> def splitList(l, s):
...     ''' l is list, s is separator, simular to split, but keep separator'''
...     i = 0
...     for _ in range(l.count(s)): # break using slices
...         e = l.index(s,i)
...         yield l[i:e+1] # sublist generator value
...         i = e+1
...     if e+1 < len(l): yield l[e+1:] # pick up
...

>>> def bharath(x,sep):
...     n = [0] + [i+1 for i,j in enumerate(x) if j == sep]
...     m= list()
...     for first, last in zip(n, n[1:]):
...         m.append(x[first:last])
...     return m
...

结果:

>>> timeit.timeit("jezrael(L, sep)", setup)
4.1499102029483765
>>> timeit.timeit("pm2ring(L, sep)", setup)
3.3499899921007454
>>> timeit.timeit("coldspeed(L, sep)", setup)
2.868469718960114
>>> timeit.timeit("juan(L, sep)", setup)
1.5428746730322018
>>> timeit.timeit("buzzycoder(L, sep)", setup)
1.5942967369919643
>>> timeit.timeit("list(splitList(L, sep))", setup)
2.7872562300181016
>>> timeit.timeit("bharath(L, sep)", setup)
2.9842335029970855

列出更大的名单:

>>> L = L*100000
>>> timeit.timeit("jezrael(L, sep)", setup, number=10)
3.3555950550362468
>>> timeit.timeit("pm2ring(L, sep)", setup, number=10)
2.337177241919562
>>> timeit.timeit("coldspeed(L, sep)", setup, number=10)
2.2037084710318595
>>> timeit.timeit("juan(L, sep)", setup, number=10)
1.3625159269431606
>>> timeit.timeit("buzzycoder(L, sep)", setup, number=10)
1.4375156159512699
>>> timeit.timeit("list(splitList(L, sep))", setup, number=10)
1.6824725979240611
>>> timeit.timeit("bharath(L, sep)", setup, number=10)
1.5603888860205188

警告

考虑到sepL的比例,结果无法解决这些问题,这会影响其中某些解决方案的时间安排。< p>

答案 3 :(得分:3)

我的解决方案是:

from  itertools import groupby

sep = ('.','ZZ')
new_L = [list(g) + [sep] for k, g in groupby(L, lambda x: x==sep) if not k] 
print (new_L)
[[('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), ('.', 'ZZ')], 
 [('You', 'WW'), ('are', 'XX'), ('cool', 'YY'), ('.', 'ZZ')]]

但我相信也存在更好/更快的解决方案。

答案 4 :(得分:3)

a = list()
start = 0
while start < len(l) and (l.index(sep, start) != -1):
    end = l.index(sep, start) + 1
    a.append(l[start:end])
    start = end

这将是我的解决方案。它简单易读。

答案 5 :(得分:2)

使用zip进行枚举和创建对的另一种解决方案

def bharath(x,sep):
    n = [0] + [i+1 for i,j in enumerate(x) if j == sep]
    m= list()
    for first, last in zip(n, n[1:]):
        m.append(x[first:last])
    return m

%%timeit
bharath(L,('.','ZZ'))
100000 loops, best of 3: 3.74 µs per loop
L = L*100000
bharath(L,('.','ZZ'))
1 loop, best of 3: 240 ms per loop 

答案 6 :(得分:1)

使用生成器和切片非常快:

String info = scanner.nextLine();

您也可以使用其他列表和分隔符。

String info = scanner.next();