python 列表偏平化 & 生成器+裝飾器的解決思路

1、

這兩天有個朋友問我,如果列表a = [1,2,[3,4],[[5,6,7]]]  轉化成 b=[1,2,3,4,5,6,7]怎麼搞? 不能用額外的變量呦。

第一反應是遞歸呀,思路很清晰。可是!我回到家想了20分鐘才拼出來代碼。。

a = [1,2,[3,4],[[5,6,7]]]
print a

def func(lst):
    if not lst:
        return []
    for i in lst:
        if isinstance(i, list):
            lst.remove(i)
            return func(i) + func(lst)
        else:
            lst.remove(i)
            return [i] + func(lst)

print func(a)
結果:
D:\projects\myapp>python 1.py
[1, 2, [3, 4], [[5, 6, 7]]]
[1, 2, 3, 4, 5, 6, 7]
遞歸的思路就是,只要是列表,我就往下一層走。一直走到盡頭,就是int的數值咯。

然後把這個數值收集起來+去掉這個數字的遞歸結果,返回給上一層。
感覺有點像2分。遞歸不要想,越想越亂,只要記住你到了最後一層,要做什麼就行了。


更新於2018年3月31日 星期六:

用生成器,不過也是用到了上述的遞歸思想。。。

# coding=utf-8
def flatten(nested):
    try:
        # 如果是字符串,那麼手動拋出TypeError。
        if isinstance(nested, str):
            raise TypeError
        for sublist in nested:
            for element in flatten(sublist):
                yield element
    except TypeError:
        yield nested


L = ['aaadf', [1, 2, 3], 2, 4, [5, [6, [8, [9]], 'ddf'], 7]]
for num in flatten(L):
    print(num)


2、

這個就吊了,我想了一個晚上還沒想出來。

假設有個生成器:

def foo():
    for i in range(10):
        yield i
我們這麼調用:

    for i in foo():
        print i
就能不斷拿到1至10。

現在請你給foo()加一個裝飾器,使其每一次迭代能拿到[1,2]兩個元素組成的list。

吊吧,裝飾器+生成器,混在一起我還真的有點懵逼。

基本思路:裝飾器修飾foo(),返回的應該還是必須個生成器。

def wrapper(func):
    def new_func(*args, **kwargs):
        a = func(*args, **kwargs)  # a還是個生成器
        return a  
    return new_func

@wrapper
def foo():
    for i in range(10):
        print "###",i
        yield i

if __name__ == '__main__':
    for i in foo():
        print i

以上代碼只能保證加了裝飾器的生成器不會出bug,但是真的不會改裝呢,備份下,明天繼續研究。

嗯,第二天開始谷歌了,還是沒啥思路呢。要不賴皮點,這麼寫:

# coding=utf-8

def wrapper(gen):
    def new_gen(*args, **kwargs):
        lst = list(gen(*args, **kwargs))
        n = 4
        return [lst[i:i+n] for i in range(0, len(lst), n)]
    return new_gen

@wrapper
def foo():
    for i in range(10):
        yield i


if __name__ == '__main__':
    for i in foo():
        print i
結果:

[0, 1, 2, 3]
[4, 5, 6, 7]
[8, 9]
呵,實現是實現了,就是覺得傻逼。竟然先把這個生成器->list,然後對list等分。感覺這不是正確的解決方案。一定有正確的方法的。

想了下,裝飾器返回一個生成器在,這個邏輯是不會錯的。

def wrapper(gen):
    def new_gen(*args, **kwargs):
        g = gen(*args, **kwargs)
        while True: 
            a,b,c,d = g.next(),g.next(),g.next(),g.next()
            yield [a,b,c,d]
    return new_gen

@wrapper
def foo():
    for i in range(10):
        yield i


if __name__ == '__main__':
    for i in foo():
        print i
結果:
[0, 1, 2, 3]
[4, 5, 6, 7]
哎,還是不大對的感覺,最後的[8,9]怎麼搞?不過思路應該差不多,這裏面是一個生成器了呢。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章