摆脱循环

时间:2014-10-02 08:06:07

标签: python iteration

最近,我写了这段代码。这将获得一个布尔值列表,其中包含所有False值散布在n True值的值。像这样:

[False, False, False, True, True, False, False, False, True, True, True, False]
#                     [island 1]                       [   island 2    ]

现在我想将这些分成n列表,其中每个岛都被分离。对于上面的列表,我会得到:

[[False, False, False, True, True, False, False, False, False, False, False, False], #-> list has island 1
 [False, False, False, False, False, False, False, False, True, True, True, False]] #-> list has island 2

这是我用来解决问题的程序:

import itertools as it

def getPosList(x):

    segs = [ (s[0], list(s[1])) for s in  it.groupby(x)]

    allSegs = [ []  for s in segs if s[0] ]

    i = 0

    for s in segs:
        s1, s2 = s
        s2 = list(s2)

        if s1:
            for j, s in enumerate(allSegs):
                if i == j: s += s2
                else:      s += len(s2)*[False]
            i += 1
        else:
            for s in allSegs: s += s2

    return allSegs 

if __name__ == '__main__':

    print getPosList([False, False, False, True, True, False, False, False, True, True, True, False])

这看起来非常具有循环和虚拟变量的非语音。我觉得应该有一个比我刚写的更优雅的解决方案。与dropwhilereduce等有关。但是,我似乎无法想出更好的东西。有关改进的建议吗?每当我看到这段丑陋的代码时,我都会畏缩。

编辑:

我从feseje那里获取灵感并提出了一个递归版本。

import itertools as it

def ppListTF(xs):
    return '[' + '|'.join([ '#' if x else ' '  for x in xs ]) + ']'

def getPosList1(x):
    '''
    '''
    if x == []: return []
    curX     = list(it.takewhile(lambda m: m == x[0] , x))
    nextVals = getPosList1(list(it.dropwhile(lambda m: m == x[0], x)))
    curX1    = [False]*len(curX)
    if nextVals:
        curX2    = [False]*len(nextVals[0])

    if x[0]:
        # The first element is True. Split the list here
        if nextVals: return [curX+curX2] + [ curX1+j for j in nextVals] 
        else:        return   [curX] + [curX1]

    else:
        # Just add the series of False to whatever is returned
        if nextVals: return [ curX+j for j in nextVals]
        else:        return   [curX]


if __name__ == '__main__':

    inp = [False, False, False, True, True, False, False, False, True, True, True, False, True, True, False, False, False, False]
    val = getPosList1(inp)
    if any(inp):
        val = filter( any, val )

    print 'i', ppListTF(inp)
    for i, v in enumerate(val):
        print i, ppListTF(v)

我仍然喜欢Hrabals的回答。这是最好的。感谢所有发布答案的人。

3 个答案:

答案 0 :(得分:2)

为了简洁,我将使用0和1。这是Python 2.7。并不是因为结果如此疯狂,但也许它会给你一些其他想法。

from itertools import *

a = map(int, list('1000111001001'))

start_indices = [i[0] for i in list(enumerate(zip(a, [0]+a))) if i[1] == (1, 0)]
# [0, 4, 9, 12]

get_island_length = lambda i: len(list(takewhile(lambda x: x, a[i:])))

pad = lambda b: b + [0]*(len(a)-len(b))

islands = [pad([0]*i + [1]*get_island_length(i)) for i in start_indices]

[''.join(map(str, i)) for i in islands]
# ['1000000000000', '0000111000000', '0000000001000', '0000000000001']

答案 1 :(得分:2)

与克里斯·马丁的答案类似的方法,但没有lambdas,只是列表理解:

islands = [False, False, False, True, True, False, False, False, True, True, True, False]
islands_starts = [v[0]+1 for v in list(enumerate(zip(islands, islands[1:]))) if v[1] == (False, True)]
#[3, 8]
islands_ends = [v[0] for v in list(enumerate(zip(islands, islands[1:]))) if v[1] == (True, False)]
#[4, 10]
separated_islands = [[False if p not in range(i[0],i[1]+1) else True for p in range(0,len(islands))] for i in zip(islands_starts,islands_ends)]
#[[False, False, False, True, True, False, False, False, False, False, False, False],
#[False, False, False, False, False, False, False, False, True, True, True, False]]

答案 2 :(得分:1)

虽然我同意@grc这在这里不是一个合适的问题,但我想指出你只需要一次迭代即可。你可以逐个处理这些元素,并在你遇到一个岛时创建一个新的列表。

 def separateIslands(islandSegments):
     separateIslands = []
     empty = [False for x in islandSegments]

     for i in range(0, len(islandSegments)-1):
         if islandSegments[i]:
             if i == 0 or not islandSegments[i-1]:
                 separateIslands.append(empty)

             separateIslands[len(separateIslands) - 1][i] = True;

     return separateIslands

 islandSegments = [False, False, False, True, True, False, False, False, True, True, True, False]
 print separateIslands(islandSegments)

这可能不是更多的“pythonian”,但仍然是一种简化:)