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

Python2.7 – a list.remove(item) egy cikluson belül váratlan viselkedést eredményez [duplikáció]

El akarom távolítani az összes páros számot a listából. De valami megzavart... Ez a kód.

lst = [4,4,5,5]

for i in lst:
    if i % 2 == 0:
        print i
        lst.remove(i)

print lst

Kinyomtatja [4, 5, 5] Miért nem [5, 5]?

17.08.2015

  • Módosítja a listát, miközben ismételget rajta. Ez megzavarja az iterációt. 17.08.2015

Válaszok:


1

Ilyennek kell lennie

for i in lst[:]:
    if i % 2 == 0:
        print i
        lst.remove(i)

print lst

Probléma:

Módosítja a listát, miközben ismételget rajta. Emiatt az iteráció leáll, mielőtt befejeződhetne

Megoldás:

Ismételheti a lista másolatát

Használhatja a list comprehension :

lst=[i for i in lst if i%2 != 0]
17.08.2015
  • @Sam mindenesetre szívesen segít 17.08.2015

  • 2

    A list.remove használatával módosítja a listát az iteráció során. Ez megszakítja az iterációt, és váratlan eredményeket kap.

    Az egyik megoldás egy új lista létrehozása a filter vagy a listaértelmezés használatával:

    >>> filter(lambda i: i % 2 != 0, lst)
    [5, 5]
    >>> [i for i in lst if i % 2 != 0]
    [5, 5]
    

    Ha szükséges, bármelyik kifejezést hozzárendelheti a lst-hez, de ezekkel a metódusokkal nem kerülheti el az új listaobjektum létrehozását.

    17.08.2015

    3

    Más válaszok már említették, hogy módosítja a listát, miközben iterál rajta, és jobb módszereket kínáltak erre. Én személy szerint jobban szeretem a listaértési módszert:

    odd_numbers = [item for item in numbers if item % 2 != 0]
    

    A megadott esetedben egy nagyon kis lista esetén én mindenképpen ezt választanám.

    Ez azonban egy új listát hoz létre, ami problémát jelenthet, ha nagyon nagy listája van. Egész számok esetében a nagy valószínűleg legalább milliókat jelent, de hogy pontos legyek, bármilyen nagynak kell lennie ahhoz, hogy memóriahasználati problémákat okozzon. Ebben az esetben itt van néhány módszer.

    Az egyik mód hasonló a kérdésben szereplő kód szándékához. Iterálhatja a listát, miközben menet közben eltávolítja a páros számokat. Azonban, hogy elkerülje azokat a problémákat, amelyeket az iterált lista módosítása okozhat, ismételje meg visszafelé. Vannak módok a továbblépésre, de ez egyszerűbb.

    Íme az egyik módja a while ciklus használatának:

    # A one hundred million item list that we don't want to copy
    # even just the odd numbers from to put into a new list.
    numbers = range(100000000)  # list(range(100000000)) in Python 3
    
    index = len(numbers) - 1  # Start on the index of the last item
    while index >= 0:
        if numbers[index] % 2 == 0:
            numbers.pop(index)
        index -= 1
    

    Íme egy másik módja a for ciklus használatának:

    # A one hundred million item list that we don't want to copy
    # even just the odd numbers from to put into a new list.
    numbers = range(100000000)  # list(range(100000000)) in Python 3
    
    for index in xrange(len(numbers) - 1, -1, -1):  # range(...) in Python 3
        if numbers[index] % 2 == 0:
            numbers.pop(index)
    

    Figyeljük meg mind a while ciklusos, mind a for ciklusos verzióban, én a numbers.pop(index)-t használtam, nem a numbers.remove(numbers[index])-t. Először is, a .pop() sokkal hatékonyabb, mert ez biztosítja az indexet, míg a .remove()-nek a listában kell keresnie az érték első előfordulását. Másodszor, vedd észre, hogy azt mondtam: "az érték első előfordulása". Ez azt jelenti, hogy kivéve, ha minden elem egyedi, a .remove() használata egy másik elemet távolít el, mint amilyenben a hurok jelenleg van, ami végül az aktuális elemet hagyja a listában.

    Még egy megoldást szeretnék megemlíteni olyan helyzetekre, amikor meg kell őriznie az eredeti listát, de nem szeretne túl sok memóriát használni a páratlan számok másolatának tárolására. Ha csak egyszer szeretné átmásolni a páratlan számokat (vagy annyira ódzkodik a memóriahasználattól, hogy inkább újraszámolja a dolgokat, amikor szükséges), használhat generátort. Ezzel lehetővé tenné, hogy a listában szereplő páratlan számok felett ismételjen anélkül, hogy bármilyen további memóriára lenne szüksége, eltekintve a generátormechanizmus által felhasznált jelentéktelen mennyiségtől.

    A generátor kifejezés pontosan úgy van definiálva, mint egy listaértelmezés, azzal a különbséggel, hogy szögletes zárójelek helyett zárójelben van:

    odd_numbers = (item for item in numbers if item % 2 != 0)
    

    Ne feledje, hogy a generátor kifejezés az eredeti listán ismétlődik, így az eredeti lista köztes iterációjának módosítása ugyanazokat a problémákat okozza, mint a lista módosítása, miközben egy for ciklusban iterál rajta. Valójában maga a generátor kifejezés egy for ciklust használ.

    Félretéve, a generátor kifejezéseket nem szabad csak nagyon nagy listákra helyezni; Mindig használom őket, amikor nem kell egy teljes listát kiszámolnom.

    Összegzés / TLDR:

    A „legjobb” módszer attól függ, hogy pontosan mit csinálsz, de ennek sok helyzetre ki kell terjednie.

    Tételezzük fel, hogy a listák "kicsiek" vagy "nagyok":

    Ha a listája kicsi, használja a lista megértését (vagy akár a generátor kifejezést, ha tudja). Ha nagy, olvass tovább.

    Ha nincs szüksége az eredeti listára, használja a while ciklus vagy a for ciklus metódusait a páros számok teljes eltávolításához (bár .pop(), nem .remove()). Ha szüksége van az eredeti listára, olvassa el.

    Ha csak egyszer iterál a páratlan számok felett, használja a generátor kifejezést. Ha többször iterálja őket, de hajlandó megismételni a számítást a memória megtakarítása érdekében, használja a generátor kifejezést.

    Ha túl sokszor iterálja a páratlan számokat ahhoz, hogy minden alkalommal újraszámítsa őket, vagy véletlenszerű hozzáférésre van szüksége, akkor a listaértelmezés segítségével készítsen új listát, amelyben csak a páratlan számok szerepelnek. Sok memóriát fog igénybe venni, de ezek a szünetek.

    17.08.2015
  • @Sam, szívesen. Ne felejtsd el pozitívan szavazni a jó válaszokra (nem csak az enyémekre), és fogadd el azt, amelyik a legjobban segít (még akkor is, ha nem az enyém :P). Ez a SO mód. 17.08.2015

  • 4

    Általános elv, hogy ne módosítsa a gyűjteményt, miközben iterál rajta. Ez egyes elemek kihagyásához és bizonyos esetekben indexhibához vezet.

    Ahelyett, hogy eltávolítana elemeket a listáról, egyszerűbb lenne, ha létrehozna egy másik, azonos nevű hivatkozást. Kisebb időbonyolítással is rendelkezik.

    lst = filter(lambda i: i % 2 !=0, lst)
    
    17.08.2015
  • Igen, ez teljesen normális. Kérjük, jelölje meg helyes válaszként, ha segített 17.08.2015
  • Ú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..