반복하는 동안 목록에서 항목을 제거하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1207406

  •  05-07-2019
  •  | 
  •  

문제

저는 Python에서 튜플 목록을 반복하고 있으며 특정 기준을 충족하면 제거하려고 합니다.

for tup in somelist:
    if determine(tup):
         code_to_remove_tup

대신 무엇을 사용해야합니까? code_to_remove_tup?이런 방식으로 항목을 제거하는 방법을 알 수 없습니다.

도움이 되었습니까?

해결책

목록 이해력을 사용하여 제거하고 싶지 않은 요소 만 포함 된 새 목록을 만들 수 있습니다.

somelist = [x for x in somelist if not determine(x)]

또는 슬라이스에 할당함으로써 somelist[:], 기존 목록을 원하는 항목 만 포함하도록 돌연변이 할 수 있습니다.

somelist[:] = [x for x in somelist if not determine(x)]

이 접근법은 다른 참조가있는 경우 유용 할 수 있습니다. somelist 변화를 반영해야합니다.

이해 대신에 사용할 수도 있습니다 itertools. Python 2에서 :

from itertools import ifilterfalse
somelist[:] = ifilterfalse(determine, somelist)

또는 Python 3에서 :

from itertools import filterfalse
somelist[:] = filterfalse(determine, somelist)

다른 팁

목록 이해력을 제안하는 답변은 거의 정확합니다. 완전히 새로운 목록을 작성한 다음 이전 목록과 동일한 이름을 지정한다는 점을 제외하고는 이전 목록을 수정하지 않습니다. 그것은 당신이 선택적 제거를 통해하고있는 것과 다릅니다. @Lennart의 제안 - 더 빠르지 만 여러 참조를 통해 목록에 액세스하면 참조 중 하나를 다시 시작하고 목록 객체 자체를 변경하지 않으면 미묘하고 비참한 버그로 이어질 수 있습니다.

다행히도 목록 이해력의 속도와 바닥 변경의 필요한 의미를 모두 얻는 것은 매우 쉽습니다.

somelist[:] = [tup for tup in somelist if determine(tup)]

다른 답변과의 미묘한 차이점에 주목하십시오. 내용물 동일한 Python 목록 개체 내에서, 다른 답변과 같이 한 참조 (이전 목록 개체에서 새 목록 개체에 이르기까지)를 다시 예약하는 대신.

목록의 사본을 가져 와서 먼저 반복해야합니다. 그렇지 않으면 예기치 않은 결과가 발생할 수있는 반복이 실패합니다.

예를 들어 (목록 유형에 따라 다름) :

for tup in somelist[:]:
    etc....

An example:

>>> somelist = range(10)
>>> for x in somelist:
...     somelist.remove(x)
>>> somelist
[1, 3, 5, 7, 9]

>>> somelist = range(10)
>>> for x in somelist[:]:
...     somelist.remove(x)
>>> somelist
[]
for i in range(len(somelist) - 1, -1, -1):
    if some_condition(somelist, i):
        del somelist[i]

그렇지 않으면 거꾸로 가야합니다. 그렇지 않으면 그것은 당신이 앉아있는 나무 지점에서 톱을 떼는 것과 비슷합니다 :-)

Python 2 사용자 : 교체 range ~에 의해 xrange 하드 코드 목록을 작성하지 않으려는

그러한 예를위한 최선의 접근 방식은 이해력을 나열하십시오

somelist = [tup for tup in somelist if determine(tup)]

전화하는 것보다 더 복잡한 일을하는 경우 determine 기능, 나는 새로운 목록을 구성하는 것을 선호하고 내가 갈 때 간단히 추가하는 것을 선호합니다. 예를 들어

newlist = []
for tup in somelist:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)
somelist = newlist

사용 목록을 복사합니다 remove 아래 답변 중 하나에 설명 된대로 코드가 조금 더 깨끗하게 보이게 할 수 있습니다. 여기에는 전체 목록을 먼저 복사하고 수행하는 것이 포함되므로 매우 큰 목록에 대해서는 확실히이 작업을 수행해서는 안됩니다. O(n) remove 제거되는 각 요소에 대한 작업은 O(n^2) 연산.

for tup in somelist[:]:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)

공식 Python 2 튜토리얼 4.2."진술용"

https://docs.python.org/2/tutorial/controlflow.html#for-statements

문서의 이 부분에서는 다음을 명확하게 설명합니다.

  • 수정하려면 반복된 목록의 복사본을 만들어야 합니다.
  • 이를 수행하는 한 가지 방법은 슬라이스 표기법을 사용하는 것입니다. [:]

루프 내에서 반복하는 시퀀스를 수정해야 하는 경우(예: 선택한 항목 복제) 먼저 복사본을 만드는 것이 좋습니다.시퀀스를 반복한다고 해서 암시적으로 복사본이 만들어지는 것은 아닙니다.슬라이스 표기법을 사용하면 이 작업이 특히 편리해집니다.

>>> words = ['cat', 'window', 'defenestrate']
>>> for w in words[:]:  # Loop over a slice copy of the entire list.
...     if len(w) > 6:
...         words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']

파이썬 2 문서 7.3."for 문"

https://docs.python.org/2/reference/compound_stmts.html#for

문서의 이 부분에서는 복사본을 만들어야 한다고 다시 한 번 말하고 실제 제거 예를 제공합니다.

메모:루프에 의해 시퀀스가 ​​수정될 때 미묘함이 있습니다(이는 변경 가능한 시퀀스에서만 발생할 수 있습니다.기울기).내부 카운터는 다음에 어떤 항목이 사용되는지 추적하는 데 사용되며, 이는 반복할 때마다 증가됩니다.이 카운터가 시퀀스 길이에 도달하면 루프가 종료됩니다.이는 모음이 시퀀스에서 현재(또는 이전) 항목을 삭제하면 다음 항목은 건너뛰게 된다는 것을 의미합니다(이미 처리된 현재 항목의 인덱스를 가져오기 때문입니다).마찬가지로, 모음이 현재 항목 앞에 항목을 시퀀스에 삽입하면 현재 항목은 다음에 루프를 통해 다시 처리됩니다.이는 전체 시퀀스의 일부를 사용하여 임시 복사본을 만들어 방지할 수 있는 불쾌한 버그로 이어질 수 있습니다.

for x in a[:]:
    if x < 0: a.remove(x)

그러나 나는 이 구현에 동의하지 않습니다. .remove() 반복해야합니다 전체 목록 가치를 찾으려고.

대신 다음 중 하나를 수행하세요.

  • 새로운 어레이를 처음부터 시작하고 .append() 마지막에 다시 : https://stackoverflow.com/a/1207460/895245

    이번에는 시간 효율적이지만 반복 중에 배열 복사본을 유지하므로 공간 효율성이 떨어집니다.

  • 사용 del 인덱스 포함: https://stackoverflow.com/a/1207485/895245

    이는 배열 복사본을 분배하기 때문에 공간 효율적이지만 CPython이 나열하기 때문에 시간 효율성이 떨어집니다. 동적 배열로 구현됩니다..

    즉, 항목을 제거하려면 다음 항목을 모두 하나씩 뒤로 이동해야 하며, 이는 O(N)입니다.

일반적으로 당신은 더 빨리 가고 싶어합니다 .append() 메모리가 큰 문제가 아닌 이상 기본적으로 옵션입니다.

Python이 이 작업을 더 잘 수행할 수 있을까요?

이 특정 Python API가 개선될 수 있는 것 같습니다.예를 들어 Java 대응과 비교해 보세요. 목록반복자, 이는 반복자 자체를 제외하고는 반복되는 목록을 수정할 수 없다는 점을 명확하게 하고 목록을 복사하지 않고도 이를 수행할 수 있는 효율적인 방법을 제공합니다.

아마도 근본적인 근거는 Python 목록이 동적 배열 기반으로 가정되므로 모든 유형의 제거는 어쨌든 시간이 비효율적이지만 Java는 두 가지 모두를 갖춘 더 좋은 인터페이스 계층 구조를 가지고 있다는 것입니다. ArrayList 그리고 LinkedList 구현 ListIterator.

Python stdlib에도 명시적인 연결 목록 유형이 없는 것 같습니다. 파이썬 연결리스트

기능 프로그래밍을 좋아하는 사람들을 위해 :

somelist[:] = filter(lambda tup: not determine(tup), somelist)

또는

from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))

현재 목록 항목이 원하는 기준을 충족하는 경우 새 목록 만 작성하는 것도 현명 할 수 있습니다.

그래서:

for item in originalList:
   if (item != badValue):
        newList.append(item)

새로운 목록 이름으로 전체 프로젝트를 다시 코딩하지 않아도됩니다.

originalList[:] = newList

Python 문서의 참고 사항 :

copy.copy (x) x의 얕은 사본을 반환합니다.

copy.deepcopy (x) x의 깊은 사본을 반환합니다.

나는 큰 목록으로 이것을해야했고, 목록을 복제하는 것은 비싸게 보였습니다. 특히 제 경우에는 남아있는 항목에 비해 삭제 수가 적기 때문입니다. 나는이 낮은 수준의 접근 방식을 취했습니다.

array = [lots of stuff]
arraySize = len(array)
i = 0
while i < arraySize:
    if someTest(array[i]):
        del array[i]
        arraySize -= 1
    else:
        i += 1

내가 모르는 것은 몇 가지 삭제가 큰 목록을 복사하는 것과 비교되는 것입니다. 통찰력이 있으면 의견을 제시하십시오.

이 답변은 원래 중복으로 표시된 질문에 대한 응답으로 작성되었습니다.파이썬의 목록에서 좌표 제거

코드에는 두 가지 문제가 있습니다.

1) remove ()를 사용할 때는 정수를 제거하려고 시도하지만 튜플을 제거해야합니다.

2) FER 루프는 목록에 항목을 건너 뜁니다.

코드를 실행할 때 발생하는 일을 실행합시다.

>>> L1 = [(1,2), (5,6), (-1,-2), (1,-2)]
>>> for (a,b) in L1:
...   if a < 0 or b < 0:
...     L1.remove(a,b)
... 
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
TypeError: remove() takes exactly one argument (2 given)

첫 번째 문제는 'a'와 'b'를 모두 전달하여 ()를 제거하지만 제거 ()는 단일 인수 만 받아 들인다는 것입니다. 그렇다면 어떻게 remove ()가 귀하의 목록과 제대로 작동하도록 할 수 있습니까? 목록의 각 요소가 무엇인지 알아 내야합니다. 이 경우 각각은 튜플입니다. 이를 보려면 목록의 한 요소에 액세스하겠습니다 (색인화가 0에서 시작) :

>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>

아하! L1의 각 요소는 실제로 튜플입니다. 그래서 우리가 제거하기 위해 통과 해야하는 것입니다 (). 파이썬의 튜플은 매우 쉽고 괄호 안에 값을 둘러싸고 단순히 만들어집니다. "A, B"는 튜플이 아니지만 "(A, B)"는 튜플입니다. 따라서 코드를 수정하고 다시 실행합니다.

# The remove line now includes an extra "()" to make a tuple out of "a,b"
L1.remove((a,b))

이 코드는 오류없이 실행되지만 출력 목록을 살펴 보겠습니다.

L1 is now: [(1, 2), (5, 6), (1, -2)]

왜 (1, -2)가 여전히 목록에 있습니까? 루프를 사용하여 반복을 반복하는 동안 목록을 수정하는 것은 특별한주의가없는 매우 나쁜 생각입니다. (1, -2)가 목록에 남아있는 이유는 목록 내 각 항목의 위치가 For 루프의 반복 사이에 변경 되었기 때문입니다. 위의 코드를 더 긴 목록으로 먹으면 어떻게되는지 살펴 보겠습니다.

L1 = [(1,2),(5,6),(-1,-2),(1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
### Outputs:
L1 is now: [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

이 결과에서 추론 할 수 있듯이 조건부 명령문이 True로 평가되고 목록 항목이 제거 될 때마다 다음 루프의 다음 반복은 값이 다른 지수에 위치하기 때문에 목록의 다음 항목의 평가를 건너 뛸 수 있습니다.

가장 직관적 인 솔루션은 목록을 복사 한 다음 원본 목록을 반복하고 사본 만 수정하는 것입니다. 다음과 같이 시도 할 수 있습니다.

L2 = L1
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
print L2 is L1
del L1
L1 = L2; del L2
print ("L1 is now: ", L1)

그러나 출력은 이전과 동일합니다.

'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

L2를 만들 때 Python은 실제로 새 개체를 만들지 않았기 때문입니다. 대신, 그것은 단지 L2를 L1과 동일한 대상으로 참조했습니다. 우리는 단순히 "평등"(==)과 다른 'is'로 이것을 확인할 수 있습니다.

>>> L2=L1
>>> L1 is L2
True

copy.copy ()를 사용하여 실제 사본을 만들 수 있습니다. 그런 다음 모든 것이 예상대로 작동합니다.

import copy
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
L2 = copy.copy(L1)
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
del L1
L1 = L2; del L2
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

마지막으로, 완전히 새로운 L1 사본을 만드는 것보다 더 깨끗한 솔루션이 있습니다. Reversed () 함수 :

L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
for (a,b) in reversed(L1):
    if a < 0 or b < 0 :
        L1.remove((a,b))
print ("L1 is now: ", L1)
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

불행히도, 나는 Reversed ()가 어떻게 작동하는지 적절하게 설명 할 수 없습니다. 목록이 전달되면 'listreverSeiterator'객체를 반환합니다. 실질적인 목적을 위해, 당신은 그것을 반대 된 논증 사본을 만드는 것으로 생각할 수 있습니다. 이것이 제가 추천하는 솔루션입니다.

반복 중에 다른 작업을 수행하려면 인덱스 (예 : 딕트 목록이있는 경우 참조를 참조 할 수 있음을 보장하는 것이 좋음)와 실제 목록 항목 내용을 모두 얻는 것이 좋을 수 있습니다.

inlist = [{'field1':10, 'field2':20}, {'field1':30, 'field2':15}]    
for idx, i in enumerate(inlist):
    do some stuff with i['field1']
    if somecondition:
        xlist.append(idx)
for i in reversed(xlist): del inlist[i]

enumerate 항목과 인덱스에 한 번에 액세스 할 수 있습니다. reversed 나중에 삭제하려는 지수가 변경되지 않도록합니다.

사용하고 싶을 수도 있습니다 filter() 내장으로 제공됩니다.

자세한 사항은 여기를 확인하십시오

리버스로 루핑을 시도 할 수 있으므로 sode_list의 경우 다음과 같은 작업을 수행 할 수 있습니다.

list_len = len(some_list)
for i in range(list_len):
    reverse_i = list_len - 1 - i
    cur = some_list[reverse_i]

    # some logic with cur element

    if some_condition:
        some_list.pop(reverse_i)

이런 식으로 인덱스가 정렬되며 목록 업데이트가 발생하지 않습니다 (팝 큐어 요소 여부에 관계없이).

하나의 가능한 솔루션은 몇 가지를 제거 할뿐만 아니라 단일 루프에서 모든 요소로 무언가를 수행하려는 경우 유용합니다.

alist = ['good', 'bad', 'good', 'bad', 'good']
i = 0
for x in alist[:]:
    if x == 'bad':
        alist.pop(i)
        i -= 1
    # do something cool with x or just print x
    print(x)
    i += 1

여기의 대부분의 답변은 목록의 사본을 만들기를 원합니다. 목록이 매우 길었던 유스 케이스가 있었고 (110k 항목) 목록을 계속 줄이는 것이 더 똑똑했습니다.

우선 당신은 필요합니다 Foreach 루프를 While 루프로 교체하십시오,

i = 0
while i < len(somelist):
    if determine(somelist[i]):
         del somelist[i]
    else:
        i += 1

의 가치 i 이전 항목이 삭제되면 동일한 인덱스에서 새 항목의 값을 얻기를 원하기 때문에 IF 블록에서 변경되지 않습니다.

나는 비슷한 일을해야했고 내 경우에는 문제가 메모리였습니다. 목록 내에서 여러 데이터 세트 객체를 새로운 객체로 수행 한 후에는 합병 한 각 항목을 제거해야했습니다. 그들 모두를 복제하고 기억을 날려 버리지 마십시오. 제 경우에는 목록 대신 사전에 객체를 갖는 것이 잘 작동했습니다.

```

k = range(5)
v = ['a','b','c','d','e']
d = {key:val for key,val in zip(k, v)}

print d
for i in range(5):
    print d[i]
    d.pop(i)
print d

```

TLDR:

나는 당신이 이것을 할 수 있는 라이브러리를 작성했습니다:

from fluidIter import FluidIterable
fSomeList = FluidIterable(someList)  
for tup in fSomeList:
    if determine(tup):
        # remove 'tup' without "breaking" the iteration
        fSomeList.remove(tup)
        # tup has also been removed from 'someList'
        # as well as 'fSomeList'

가능하면 반복하는 동안 반복 가능한 항목을 수정할 필요가 없는 다른 방법을 사용하는 것이 가장 좋지만 일부 알고리즘의 경우 그렇게 간단하지 않을 수 있습니다.따라서 원래 질문에 설명된 코드 패턴을 정말로 원한다고 확신한다면 가능합니다.

목록뿐만 아니라 모든 변경 가능한 시퀀스에서 작동해야 합니다.


전체 답변:

편집하다:이 답변의 마지막 코드 예제는 다음에 대한 사용 사례를 제공합니다. 때로는 목록 이해를 사용하는 대신 목록을 수정하고 싶을 수도 있습니다.답변의 첫 번째 부분은 다음의 튜토리얼 역할을 합니다. 어떻게 배열은 그 자리에서 수정될 수 있습니다.

해결책은 다음과 같습니다. 이것 보낸 사람의 답변(관련 질문에 대한)입니다.수정된 목록을 반복하는 동안 배열 인덱스가 업데이트되는 방법을 설명합니다.아래 솔루션은 목록이 수정되더라도 배열 인덱스를 올바르게 추적하도록 설계되었습니다.

다운로드 fluidIter.py ~에서 여기 https://github.com/alanbacon/FluidIterator, 단일 파일이므로 git을 설치할 필요가 없습니다.설치 프로그램이 없으므로 파일이 Python 경로에 있는지 확인해야 합니다.코드는 Python 3용으로 작성되었으며 Python 2에서는 테스트되지 않았습니다.

from fluidIter import FluidIterable
l = [0,1,2,3,4,5,6,7,8]  
fluidL = FluidIterable(l)                       
for i in fluidL:
    print('initial state of list on this iteration: ' + str(fluidL)) 
    print('current iteration value: ' + str(i))
    print('popped value: ' + str(fluidL.pop(2)))
    print(' ')

print('Final List Value: ' + str(l))

그러면 다음과 같은 출력이 생성됩니다.

initial state of list on this iteration: [0, 1, 2, 3, 4, 5, 6, 7, 8]
current iteration value: 0
popped value: 2

initial state of list on this iteration: [0, 1, 3, 4, 5, 6, 7, 8]
current iteration value: 1
popped value: 3

initial state of list on this iteration: [0, 1, 4, 5, 6, 7, 8]
current iteration value: 4
popped value: 4

initial state of list on this iteration: [0, 1, 5, 6, 7, 8]
current iteration value: 5
popped value: 5

initial state of list on this iteration: [0, 1, 6, 7, 8]
current iteration value: 6
popped value: 6

initial state of list on this iteration: [0, 1, 7, 8]
current iteration value: 7
popped value: 7

initial state of list on this iteration: [0, 1, 8]
current iteration value: 8
popped value: 8

Final List Value: [0, 1]

위에서 우리는 pop 유동 목록 개체에 대한 메서드입니다.다음과 같은 다른 일반적인 반복 가능한 메서드도 구현됩니다. del fluidL[i], .remove, .insert, .append, .extend.목록은 슬라이스(sort 그리고 reverse 메서드는 구현되지 않습니다).

유일한 조건은 언제든지 목록을 수정해야 한다는 것입니다. fluidL 또는 l 코드가 작동하지 않는 다른 목록 개체에 다시 할당되었습니다.원래 fluidL 객체는 여전히 for 루프에서 사용되지만 우리가 수정할 수 있는 범위를 벗어나게 됩니다.

즉.

fluidL[2] = 'a'   # is OK
fluidL = [0, 1, 'a', 3, 4, 5, 6, 7, 8]  # is not OK

목록의 현재 인덱스 값에 액세스하려는 경우 열거를 사용할 수 없습니다. 이는 for 루프가 실행된 횟수만 계산하기 때문입니다.대신 반복자 객체를 직접 사용하겠습니다.

fluidArr = FluidIterable([0,1,2,3])
# get iterator first so can query the current index
fluidArrIter = fluidArr.__iter__()
for i, v in enumerate(fluidArrIter):
    print('enum: ', i)
    print('current val: ', v)
    print('current ind: ', fluidArrIter.currentIndex)
    print(fluidArr)
    fluidArr.insert(0,'a')
    print(' ')

print('Final List Value: ' + str(fluidArr))

그러면 다음이 출력됩니다.

enum:  0
current val:  0
current ind:  0
[0, 1, 2, 3]

enum:  1
current val:  1
current ind:  2
['a', 0, 1, 2, 3]

enum:  2
current val:  2
current ind:  4
['a', 'a', 0, 1, 2, 3]

enum:  3
current val:  3
current ind:  6
['a', 'a', 'a', 0, 1, 2, 3]

Final List Value: ['a', 'a', 'a', 'a', 0, 1, 2, 3]

그만큼 FluidIterable 클래스는 원래 목록 객체에 대한 래퍼를 제공할 뿐입니다.원본 객체는 다음과 같이 유동 객체의 속성으로 액세스할 수 있습니다.

originalList = fluidArr.fixedIterable

더 많은 예제/테스트는 다음에서 찾을 수 있습니다. if __name__ is "__main__": 하단의 섹션 fluidIter.py.다양한 상황에서 어떤 일이 일어나는지 설명하기 때문에 살펴볼 가치가 있습니다.와 같은:슬라이스를 사용하여 목록의 큰 섹션을 교체합니다.또는 중첩된 for 루프에서 동일한 반복 가능 항목을 사용(및 수정)합니다.

내가 말했듯이 :이는 코드의 가독성을 떨어뜨리고 디버깅을 더욱 어렵게 만드는 복잡한 솔루션입니다.따라서 David Raznick의 글에서 언급된 목록 이해와 같은 다른 솔루션 답변 먼저 고려해야합니다.즉, 삭제해야 하는 요소의 인덱스를 추적하는 것보다 이 클래스가 나에게 유용하고 사용하기 더 쉬운 경우를 발견했습니다.


편집하다:의견에서 언급했듯이 이 답변은 실제로 이 접근 방식이 솔루션을 제공하는 문제를 제시하지 않습니다.나는 여기서 그 문제를 다루려고 노력할 것입니다:

목록 내포는 새로운 목록을 생성하는 방법을 제공하지만 이러한 접근 방식은 목록 전체의 현재 상태보다는 각 요소를 개별적으로 보는 경향이 있습니다.

즉.

newList = [i for i in oldList if testFunc(i)]

그런데 만약 결과가 나온다면? testFunc 추가된 요소에 따라 달라집니다. newList 이미?아니면 아직 요소가 oldList 그건 다음에 추가될 수도 있지 않을까요?여전히 목록 이해를 사용하는 방법이 있을 수 있지만 그 우아함을 잃기 시작할 것이며, 나에게는 목록을 제자리에서 수정하는 것이 더 쉽다고 느껴집니다.

아래 코드는 위의 문제를 겪는 알고리즘의 한 예입니다.알고리즘은 요소가 다른 요소의 배수가 되지 않도록 목록을 줄입니다.

randInts = [70, 20, 61, 80, 54, 18, 7, 18, 55, 9]
fRandInts = FluidIterable(randInts)
fRandIntsIter = fRandInts.__iter__()
# for each value in the list (outer loop)
# test against every other value in the list (inner loop)
for i in fRandIntsIter:
    print(' ')
    print('outer val: ', i)
    innerIntsIter = fRandInts.__iter__()
    for j in innerIntsIter:
        innerIndex = innerIntsIter.currentIndex
        # skip the element that the outloop is currently on
        # because we don't want to test a value against itself
        if not innerIndex == fRandIntsIter.currentIndex:
            # if the test element, j, is a multiple 
            # of the reference element, i, then remove 'j'
            if j%i == 0:
                print('remove val: ', j)
                # remove element in place, without breaking the
                # iteration of either loop
                del fRandInts[innerIndex]
            # end if multiple, then remove
        # end if not the same value as outer loop
    # end inner loop
# end outerloop

print('')
print('final list: ', randInts)

출력 및 최종 축소 목록은 다음과 같습니다.

outer val:  70

outer val:  20
remove val:  80

outer val:  61

outer val:  54

outer val:  18
remove val:  54
remove val:  18

outer val:  7
remove val:  70

outer val:  55

outer val:  9
remove val:  18

final list:  [20, 61, 7, 55, 9]

다른 답변은 일반적으로 반복되는 목록에서 삭제하는 것이 좋지 않은 생각입니다. 리버스 반복은 함정을 피하기 만하면 코드를 따르는 것이 훨씬 어렵 기 때문에 일반적으로 목록 이해력이나 목록 이해력을 사용하는 것이 좋습니다. filter.

그러나 반복하는 시퀀스에서 요소를 제거하는 것이 안전한 경우가 있습니다. 반복하는 동안 하나의 항목 만 제거하는 경우. 이것은 a를 사용하여 확인할 수 있습니다 return 또는 a break. 예를 들어:

for i, item in enumerate(lst):
    if item % 4 == 0:
        foo(item)
        del lst[i]
        break

이것은 일부 조건을 충족하는 목록의 첫 번째 항목에서 부작용으로 일부 작업을 수행 한 다음 바로 목록에서 해당 항목을 제거 할 때 목록 이해보다 이해하기 쉽습니다.

가장 효과적인 방법은 목록 이해력이며 많은 사람들이 자신의 사례를 보여줍니다. 물론 iterator ~을 통해 filter.

Filter 함수와 시퀀스를 수신합니다. Filter 전달 된 함수를 각 요소에 차례로 적용한 다음 함수 리턴 값이 의지에 따라 요소를 유지 할 것인지 파괴 할 것인지 결정합니다. True 또는 False.

예가 있습니다 (튜플의 확률을 얻음) :

list(filter(lambda x:x%2==1, (1, 2, 4, 5, 6, 9, 10, 15)))  
# result: [1, 5, 9, 15]

주의 : 반복자도 처리 할 수도 있습니다. 반복자는 때때로 시퀀스보다 낫습니다.

나는 당신의 문제를 해결하기위한 세 가지 접근법을 생각할 수 있습니다. 예를 들어, 나는 무작위 튜플 목록을 만들 것입니다. somelist = [(1,2,3), (4,5,6), (3,6,6), (7,8,9), (15,0,0), (10,11,12)]. 내가 선택한 상태는입니다 sum of elements of a tuple = 15. 최종 목록에는 합계가 15와 같지 않은 튜플 만 있습니다.

내가 선택한 것은 무작위로 선택된 예입니다. 자유롭게 바꾸십시오 그만큼 튜플 목록 그리고 상태 내가 선택한 것.

방법 1.> 제안한 프레임 워크를 사용하십시오 (For Loop의 코드를 채우는 곳). 나는 작은 코드를 사용합니다 del 상기 조건을 충족하는 튜플을 삭제합니다. 그러나이 방법은 두 개의 배치 된 튜플이 주어진 조건을 충족하면 튜플 (상기 조건을 만족)을 놓칠 것입니다.

for tup in somelist:
    if ( sum(tup)==15 ): 
        del somelist[somelist.index(tup)]

print somelist
>>> [(1, 2, 3), (3, 6, 6), (7, 8, 9), (10, 11, 12)]

방법 2.> 주어진 조건이 충족되지 않은 요소 (튜플)를 포함하는 새 목록을 구성하십시오 (이것은 주어진 조건이 충족되는 목록의 요소를 제거하는 것과 동일). 다음은 다음과 같은 코드입니다.

newlist1 = [somelist[tup] for tup in range(len(somelist)) if(sum(somelist[tup])!=15)]

print newlist1
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

방법 3.> 주어진 조건이 충족되는 지수를 찾은 다음 해당 지수에 해당하는 제거 요소 (튜플)를 사용하십시오. 다음은 코드입니다.

indices = [i for i in range(len(somelist)) if(sum(somelist[i])==15)]
newlist2 = [tup for j, tup in enumerate(somelist) if j not in indices]

print newlist2
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

방법 1 및 방법 2는 방법 3보다 빠릅니다.. 방법 2 및 방법 3은 방법 1보다 더 효율적이다. 나 방법 2를 선호합니다. 앞서 언급 한 예를 위해 time(method1) : time(method2) : time(method3) = 1 : 1 : 1.7

루프는 색인을 통해 반복됩니다 ..

목록이 있다고 생각합니다.

[5, 7, 13, 29, 65, 91]

호출 된 목록 변수를 사용하고 있습니다 lis. 그리고 당신은 똑같이 제거하여 ..

당신의 변수

lis = [5, 7, 13, 29, 35, 65, 91]
       0  1   2   3   4   5   6

5 번째 반복 중에

당신의 번호 35 프라임이 아니 었으므로 목록에서 제거했습니다.

lis.remove(y)

그리고 다음 가치 (65) 이전 색인으로 이동하십시오.

lis = [5, 7, 13, 29, 65, 91]
       0  1   2   3   4   5

그래서 4 번째 반복은 포인터가 5 위로 옮겨졌습니다 ..

그렇기 때문에 루프가 이전 인덱스로 이동 한 이후 65를 커버하지 않습니다.

따라서 사본 대신 원본을 참조하는 다른 변수로 목록을 참조해서는 안됩니다.

ite = lis #dont do it will reference instead copy

따라서 목록의 사본을 사용하십시오 list[::]

이제 당신은 줄 것입니다.

[5, 7, 13, 29]

문제는 반복 중 목록에서 값을 제거한 다음 목록 색인이 붕괴됩니다.

대신 이해를 시도 할 수 있습니다.

반복 가능한 모든 반복, 목록, 튜플, DICT, 문자열 등을 지원합니다.

정말 큰 잠재력이있는 것은 다음을 사용합니다.

import numpy as np

orig_list = np.array([1, 2, 3, 4, 5, 100, 8, 13])

remove_me = [100, 1]

cleaned = np.delete(orig_list, remove_me)
print(cleaned)

그것은 다른 무엇보다 훨씬 빠르야합니다.

어떤 상황에서는 단순히 단순히 목록을 한 번에 필터링하는 것보다 더 많은 일을하는 경우 반복하는 동안 반복이 변경되기를 원합니다.

다음은 목록을 미리 복사하는 것이 부정확하고 역 반복이 불가능하며 목록 이해도 옵션이 아닙니다.

""" Sieve of Eratosthenes """

def generate_primes(n):
    """ Generates all primes less than n. """
    primes = list(range(2,n))
    idx = 0
    while idx < len(primes):
        p = primes[idx]
        for multiple in range(p+p, n, p):
            try:
                primes.remove(multiple)
            except ValueError:
                pass #EAFP
        idx += 1
        yield p

나중에 새 목록을 사용하면 Elem을 None으로 설정 한 다음 이와 같이 나중에 루프에서 판단 할 수 있습니다.

for i in li:
    i = None

for elem in li:
    if elem is None:
        continue

이런 식으로, 당신은 목록을 복사 할 필요가 없으며 이해하기 쉽습니다.

숫자 목록을 반대하면 3으로 나눌 수있는 모든 아니오를 제거하려고합니다.

list_number =[i for i in range(100)]

사용 list comprehension, 이것은 새 목록을 캐 와이어드하고 새로운 메모리 공간을 만듭니다.

new_list =[i for i in list_number if i%3!=0]

사용 lambda filter 기능, 결과적으로 새로운 목록을 생성하고 추억 공간을 소비합니다.

new_list = list(filter(lambda x:x%3!=0, list_number))

새 목록을위한 메모리 공간을 소비하고 기존 목록을 수정하지 않고

for index, value in enumerate(list_number):
    if list_number[index]%3==0:
        list_number.remove(value)

즉시 목록의 사본을 작성하여 특정 기준을 충족하는 목록에서 튜플을 반복하고 삭제할 때 참조로이를 참조 할 수 있습니다.

그런 다음 출력에 원하는 목록의 유형에 따라 제거 된 튜플 목록이든 제거되지 않은 튜플 목록에 따라 다릅니다.

David가 지적했듯이, 나는 당신이 제거하고 싶지 않은 요소를 유지하기 위해 목록 이해를 권장합니다.

somelist = [x for x in somelist if not determine(x)]
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top