WebHU - Programozási kérdések és válaszok

Hogyan lehet egy többdimenziós listát optimálisan egyetlen elemlistává alakítani a Pythonban? [másolat]

Lehetséges ismétlődések:
Sima lista készítése a Python listáiból
Lista (egy szabálytalan) lista egyesítése a Pythonban

Írjon be egy listát, például: [1,2,[3,4,[5,6,7,[8]]],[9],10]

Kívánt kimenet: [1,2,3,4,5,6,7,8,9,10]

Jelenleg a következő rekurzív függvényem van:

def fix_list( li , l = [] ):
    for i in li:
        try:
            len( i )
            fix_list( i, l )
        except:
            l.append( i )
    return l

Úgy érzem, a try/except catch egy kicsit trükkös és lassú, és kíváncsi vagyok, van-e jobb/optimalizáltabb módja ennek a feladatnak. Minden hozzájárulást nagyra értékelünk.


  • Megpróbálhatja azt is, ha type(i) == type(1). 13.07.2011
  • Lásd itt: stackoverflow .com/questions/2158395/ 13.07.2011
  • Nagyon könnyű, ha rájössz, hogy mennyire lassú (vagy nem) a funkciód a timeit modullal. 13.07.2011
  • Tetszik ez a kérdés, mert a válaszok inkább a generátorok jó használatát mutatják be, nem pedig egy teljesen új listát. 13.07.2011

Válaszok:


1

Itt van egy iteratív verzió (eredetileg Artsiom Rudzenka ihlette), amely a helyben módosítja a listát szelet hozzárendeléssel, ahelyett, hogy minden egyes lépésnél új listát hozna létre. Érdekes módon a listán csak egyszer kell átmenni! A enumerate() használata kissé szokatlan; Arra használom, hogy nyomon követhessek egy indexet egy listába, amely növekszik, ahogy végigfutom rajta, de valójában nem a tényleges listaelemet használom.

def flattened(items, seqtypes=(list, tuple)):

    items = items[:]  # we will return a copy; remove to mutate original
    for i, _ in enumerate(items):
        while isinstance(items[i], seqtypes):
            items[i:i+1] = items[i]
    return items

print flattened([1,2,[3,4,[5,6,7,[8]]],[9],10])

Generátor verzió:

def flattener(items, seqtypes=(list, tuple)):

    items = items[:]
    for i, _ in enumerate(items):
        while isinstance(items[i], seqtypes):
            items[i:i+1] = items[i]
        yield items[i]

print list(flattener([1,2,[3,4,[5,6,7,[8]]],[9],10]))

Itt van egy list alosztály, amelynek flatten() metódusa van. A sort() és reverse() metódusokhoz hasonlóan ez is mutálja a listát, és a None értéket adja vissza.

class listy(list):

    def flatten(self, seqtypes=(list, tuple)):
        for i, _ in enumerate(self):
            while isinstance(self[i], seqtypes):
                self[i:i+1] = self[i]

lst = listy([1,2,[3,4,[5,6,7,[8]]],[9],10])
lst.flatten()
print lst

Szerk.: Ezt elég jelentősen leegyszerűsítettem az eredeti verziómhoz képest. Viszont úgy látom, a kérdés lezárva.

13.07.2011

2

Lásd ezt a választ:

def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
            for sub in flatten(el):
                yield sub
        else:
            yield el
13.07.2011
  • @Gandi: Hát legalább mondtam, hogy honnan vettem, feladó nem. 13.07.2011
  • Nem mondom, hogy semmi baj van benne. 13.07.2011
  • Ez nem jelenti azt, hogy válaszként kell közzétennie IMHO; hanem vegye figyelembe, hogy ez egy másik kérdés megkettőzése. 13.07.2011
  • @nightcracker, azért írtam, hogy megértsem, hogyan lehet rekurzív generátort létrehozni :). De hátborzongatóan hasonló, nem? 13.07.2011

  • 3

    Íme egy egyszerű generátor, amely ezt teszi:

    def flatten(nested):
        for item in nested:
            if isinstance(item, collections.Iterable) and not isinstance(item, basestring):
                for inner_item in flatten(item):
                    yield inner_item
            else:
                yield item
    

    Nem biztos benne, hogy "optimális"-e vagy sem.

    13.07.2011
  • Csak azt a megoldást másoltad át, és átnevezted a változókat, hogy a sajátod legyen? 13.07.2011
  • @phant0m, nem, egy forgatókönyvből másoltam ki, amit egy ideje írtam, hogy megértsem a rekurzív generátorokat. Engem azonban nyugtalanít a hasonlósága az egy éjszakai káposztához. 13.07.2011
  • Az enyém pontosan ugyanúgy néz ki, kivéve ha iterálhatót keresek, a hasattr(el, '__iter__') parancsot használom. A többi gyakorlatilag egyforma. Aki erre 15 percet fordít, az nagyjából ugyanerre a megoldásra jut. 13.07.2011

  • 4

    Kipróbáltam az alábbi megoldást és működik:

    data = [1,2,[3,4,[5,6,7,[8]]],[9],10]
    
    while any(isinstance(x, list) for x in data):
        tmpLst = []
        for x in data:
            if isinstance(x, list):
                tmpLst.extend(x)
            else:
                tmpLst.append(x)
        data = tmpLst
    
    13.07.2011
  • Miért készítsünk másolatot a tmpLst-ről a ciklus végén? 13.07.2011
  • @kindall - Módosítom a kezdeti listát, hogy a ciklus közben el tudjam hagyni. 13.07.2011
  • igen, de nekem úgy tűnik, hogy a data = tmpLst jól működne a szelet/másolat használata nélkül, mivel a tmpLst már az eredeti lista másolata. 13.07.2011
  • Kipróbáltam, és igen - úgy tűnik, igazad van (egyszerűen a [:]-vel használom, hogy ne kapjak hibát sekély/mély másolat esetén). 13.07.2011

  • 5

    Egy másik megközelítés..

    def flatten(old, new):                                                                                                                      
        for i in old:                                                                                                                           
            flatten(i, new) if isinstance(i, list) else new.append(i)                                                                           
        return new                                                                                                                              
    
    if __name__ == '__main__':                                                                                                                  
        l1 = [1, 2, [3, 4, [5, 6, 7, [8]]], [9], 10]                                                                                            
        l2 = list()                                                                                                                             
        l3 = flatten(l1, l2)                                                                                                                     
        print l3
    

    Leegyszerűsítve, így nem kell megadnia és üresen hagynia a listát az összelapított argumentumlistához.

    def rec_flatten(old, new=list()):                                                                                                           
        for i in old:                                                                                                                           
            rec_flatten(i, new) if isinstance(i, list) else new.append(i)                                                                       
        return new                                                                                                                              
    
    if __name__ == '__main__':                                                                                                                  
        l1 = [1, 2, [3, 4, [5, 6, 7, [8]]], [9], 10]                                                                                            
        x = rec_flatten(l1)                                                                                                                     
        print x
    
    13.07.2011
  • A második verzió több listát fog felhalmozni; próbálja meg hívni néhányszor egyetlen szkriptben. 14.07.2011
  • Új anyagok

    A rádiógomb ellenőrzött eseményének használata a jQueryben
    Ebben a cikkben látni fogjuk, hogyan kell dolgozni a jquery választógombbal ellenőrzött eseményeivel. A választógombok HTML gombok, amelyek segítenek kiválasztani egyetlen értéket egy csoportból...

    Körkörös függőségek megoldása terraformban adatforrásokkal – lépésről lépésre
    Mi az a körkörös függőségek Dolgozzunk egy egyszerű eseten, amikor az SQS-sor és az S3-vödör közötti körkörös függőség problémája van egy egymástól függő címkeérték miatt. provider..

    Miért érdemes elkezdeni a kódolást 2023-ban?
    01100011 01101111 01100100 01100101 — beep boop beep boop Világunk folyamatosan fejlődik a technológia körül, és naponta fejlesztenek új technológiákat a valós problémák megoldására. Amint..

    🎙 Random Noise #2  – Örökbefogadás és hit
    az analitika íratlan világának gondozása Szeretné, hogy ezek a frissítések a postaládájába kerüljenek? Iratkozzon fel itt . "Ha önvezető autókat gyártanak, akkor mi miért ne..

    A legrosszabb politika és prediktív modellek májátültetésre jelöltek számára az Egyesült Államokban
    A máj (vagy óangolul lifer) az emberi test legnehezebb belső szervére utal, amely csendesen működik a nap 24 órájában. Mit csinál a máj? 500 feladatot hajt végre a szervezet egészségének..

    5 webhely, amely 2022-ben fejleszti front-end fejlesztői készségeit
    Frontendmentor.io A tényleges projektek létrehozásával a Frontendmentor.io segítséget nyújt a front-end kódolási képességeinek fejlesztésében. A kódolást azután kezdheti meg, hogy..

    Mikor kell használni a Type-t az interfészhez képest a TypeScriptben?
    A TypeScript a JavaScript gépelt szuperkészlete, amely statikus gépelést ad a nyelvhez. Ez megkönnyíti a robusztus és karbantartható kód írását azáltal, hogy a hibákat a fordítási időben..