2014-10-02 131 views
0

所以最近我寫了這段代碼。這得到布爾值的列表,其包括如果所有False值穿插nTrue值。事情是這樣的:擺脫循環

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

現在我想這些分成n列出每個島嶼都seaprated。對於上面的列表中,我將獲得:

[[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]) 

這看起來很unPythonic與循環和虛擬變量。我覺得應該有比我剛纔寫的更優雅的解決方案。與dropwhile,reduce等有關。但是,我似乎無法拿出更好的東西。任何有關改進的建議?每當我看到這段醜陋的代碼時,我都會畏縮。

編輯:

我把靈感來自於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

這個問題是更適合於[代碼審查(https://codereview.stackexchange.com/ )。 – grc 2014-10-02 08:23:01

回答

2

類似的方法來克里斯·馬丁的答案,但沒有lambda表達式,只是列表解析:

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]] 
+0

這是迄今爲止我得到的最佳答案。我必須接受這一點。謝謝。 – ssm 2014-10-03 00:42:41

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」但仍然是一個簡化:)

+0

有趣。它看起來更乾淨。謝謝! – ssm 2014-10-02 08:49:13

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'] 
+0

我覺得這很酷。我認真考慮這一點。謝謝。 – ssm 2014-10-02 08:50:11