답변:
목록 이해를 사용하여 제거하지 않으려는 요소 만 포함하는 새 목록을 만들 수 있습니다.
somelist = [x for x in somelist if not determine(x)]
또는 slice에 할당 somelist[:]
하여 기존 항목을 변경하여 원하는 항목 만 포함 할 수 있습니다.
somelist[:] = [x for x in somelist if not determine(x)]
이 방법은 somelist
변경 사항을 반영해야하는 다른 참조가있는 경우 유용 할 수 있습니다 .
이해하는 대신을 사용할 수도 있습니다 itertools
. 파이썬 2에서 :
from itertools import ifilterfalse
somelist[:] = ifilterfalse(determine, somelist)
또는 파이썬 3에서 :
from itertools import filterfalse
somelist[:] = filterfalse(determine, somelist)
명확성을 기하기 위해 그리고 [:]
hackish 또는 fuzzy 표기법을 사용하는 사람들을 위해 보다 명확한 대안이 있습니다. 이론적으로는 위의 한 줄짜리 라이너와 공간 및 시간과 동일한 성능을 발휘해야합니다.
temp = []
while somelist:
x = somelist.pop()
if not determine(x):
temp.append(x)
while temp:
somelist.append(templist.pop())
또한 최소한의 수정으로 Python 목록의 항목 바꾸기 기능 이 없을 수있는 다른 언어에서도 작동합니다 . 예를 들어, 모든 언어 False
가 파이썬처럼 빈 목록을 캐스트 하지는 않습니다. while somelist:
보다 명시적인 것을 대신 할 수 있습니다 while len(somelist) > 0:
.
somelist[:] = (x for x in somelist if determine(x))
불필요한 사본을 만들 수없는 생성기를 생성 해야합니다 .
list_ass_slice()
을 구현하는 함수 . 이 함수는 항상리스트를 반환합니다. 즉 생성기 대신 이미리스트를 사용하는 @Alex Martelli의 솔루션이 가장 효율적일 것입니다.somelist[:]=
PySequence_Fast()
somelist
두 방법 모두에서 원본 목록 이 변경 되지 않습니까?
목록 이해를 제안하는 답변은 완전히 정확합니다. 단지 완전히 새로운 목록을 작성한 다음 이전 목록과 동일한 이름을 지정하면 이전 목록을 수정하지 않습니다. @Lennart의 제안 에서와 같이 선택적 제거로 수행하는 것과는 다릅니다. 더 빠르지 만 여러 참조를 통해 목록에 액세스하면 참조 중 하나만 다시하고 목록 객체를 변경하지 않는다는 사실 그 자체는 미묘하고 비참한 버그로 이어질 수 있습니다.
다행스럽게도 목록 이해 속도와 내부 변경에 필요한 의미를 모두 쉽게 얻을 수 있습니다.
somelist[:] = [tup for tup in somelist if determine(tup)]
다른 답변과의 미묘한 차이점에 유의하십시오.이 이름은 베어 이름에 할당되지 않습니다. 목록 전체에 발생하는 목록 조각에 할당되므로 하나의 참조를 다시 가져 오는 대신 동일한 Python 목록 객체 내에서 목록 내용 을 대체합니다. 다른 답변과 같이 (이전 목록 객체에서 새 목록 객체로).
a
려면를 b
사용하십시오 a.clear(); a.update(b)
.
x = ['foo','bar','baz']; y = x; x = [item for item in x if determine(item)];
이것은 x
목록 이해 결과에 다시 할당 되지만 y
여전히 원래 목록을 참조 합니다 ['foo','bar','baz']
. 동일한 목록 을 예상 x
하고 y
참조하는 경우 버그가 발생한 것일 수 있습니다. Alex가 보여주는 것처럼 전체 목록의 한 조각에 할당하여 이것을 방지하고 여기에 표시합니다 x = ["foo","bar","baz"]; y = x; x[:] = [item for item in x if determine(item)];
. 목록이 수정되었습니다. 목록 ( x
및 y
여기)에 대한 모든 참조가 새 목록을 참조하는지 확인하십시오.
filter
함수를 사용 하면 새로운리스트가 생성되고, 요소를 수정하지 않습니다 ...olist[:] = [i for i in olist if not dislike(i)]
목록의 사본을 가져 와서 먼저 반복해야합니다. 그렇지 않으면 예상치 못한 결과로 인해 반복이 실패합니다.
예를 들어 (목록 유형에 따라 다름) :
for tup in somelist[:]:
etc....
예를 들면 :
>>> 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
[]
list(somelist)
iterable을 목록으로 변환합니다. somelist[:]
슬라이싱을 지원하는 객체의 복사본을 만듭니다. 그래서 그들은 반드시 같은 것을 할 필요는 없습니다. 이 경우 나는의 사본을 만들고 싶어 somelist
내가 사용하는, 그래서 개체[:]
remove()
반복 할 때마다 WHOLE 목록을 검토해야하므로 시간이 오래 걸립니다.
for i in range(len(somelist) - 1, -1, -1):
if some_condition(somelist, i):
del somelist[i]
그렇지 않으면 거꾸로 가야합니다. 그렇지 않으면 앉아있는 나뭇 가지를 톱질하는 것과 같습니다.
파이썬 2 사용자 : 대체 range
에 의해 xrange
피하기 위해 하드 코딩 된 목록을 작성
reversed()
내장
m
시간이 느려질 수 있습니다 .
공식 파이썬 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()
반복해야하기 때문에이 구현에 동의하지 않습니다 .
최상의 해결 방법
어느 한 쪽:
https://stackoverflow.com/a/1207460/895245.append()
: 새 배열을 처음부터 새로 시작한 후 다시 시작
이 시간은 효율적이지만 반복하는 동안 어레이의 사본을 유지하기 때문에 공간이 덜 효율적입니다.
del
인덱스와 함께 사용 : https : //.com/a/1207485/895245
이것은 배열 사본을 분배하므로 공간 효율적이지만 CPython 목록 이 동적 배열로 구현 되므로 시간이 덜 효율적 입니다.
즉, 항목을 제거하려면 모든 다음 항목을 하나씩 뒤로 이동해야합니다 (O (N)).
일반적으로 .append()
메모리가 큰 문제가 아닌 한 기본적으로 더 빠른 옵션을 원합니다 .
파이썬이 더 잘 할 수 있습니까?
이 특정 Python API가 개선 될 수있는 것 같습니다. 예를 들어 다음과 비교하십시오.
std::vector::erase
요소를 제거한 후 유효한 인터 레이터를 요소에 리턴하는 C ++두 가지 모두 반복자 자체를 제외하고 반복되는 목록을 수정할 수 없다는 것을 분명히하고 목록을 복사하지 않고 효율적으로 수행 할 수있는 방법을 제공합니다.
아마도 기본 이론적 근거는 파이썬 목록이 동적 배열을 지원한다고 가정하기 때문에 어쨌든 모든 유형의 제거는 시간이 비효율적이지만 Java는의 구현 ArrayList
과 LinkedList
구현이 모두 더 좋은 인터페이스 계층 구조를 갖습니다 ListIterator
.
파이썬 stdlib에는 명시 적으로 연결된 목록 유형이없는 것 같습니다 : Python Linked List
이러한 예에 대한 가장 좋은 방법은 목록 이해입니다.
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)
기능적 프로그래밍을 좋아하는 사람들을 위해 :
somelist[:] = filter(lambda tup: not determine(tup), somelist)
또는
from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))
filter
이며 Pythonic입니다. 2. 당신은 필요한 경우 lambda
사용 map
또는 filter
목록 빌려 또는 genexpr이며, 항상 더 나은 옵션; map
및 filter
변환 / 술어 함수는 파이썬이 내장에서 C로 구현하고 반복 가능한이 하찮게 작은 아니지만, 당신이 필요로 할 때 그들은 항상 느린있을 때 약간 빠를 수 있습니다 lambda
listcomp / genexpr은 피할 수있다.
거대한 목록 으로이 작업을 수행해야했고 목록을 복제하는 것이 비용이 많이 드는 것처럼 보였습니다. 특히 필자의 경우 삭제 항목 수가 남아있는 항목과 비교할 때 적기 때문입니다. 나는이 저수준 접근법을 취했다.
array = [lots of stuff]
arraySize = len(array)
i = 0
while i < arraySize:
if someTest(array[i]):
del array[i]
arraySize -= 1
else:
i += 1
내가 모르는 것은 큰 목록을 복사하는 것보다 몇 번의 삭제가 얼마나 효율적인지입니다. 통찰력이 있으면 의견을 말하십시오.
list
리스트의 중간에서 제거하는 것은리스트의 길이에 선형 시간이 걸리기 때문에, 우선 데이터 구조로서의 선택은 신중하게 고려되어야한다. k 번째 순차 항목에 대한 임의 액세스가 실제로 필요하지 않은 경우 고려할 사항이 OrderedDict
있습니까?
newlist = []
그리고 newlist.append(array[i])
바로 전에 만들지 del array[i]
않습니까?
list()
. 링크 된 목록 인 경우 무작위 액세스는 비싸고, list()
배열 인 경우 에는 다음 요소를 모두 앞으로 이동해야하기 때문에 삭제가 비쌉니다. 알맞은 반복자는 연결 목록 구현에 좋은 것을 만들 수 있습니다. 그러나 이것은 공간 효율적일 수 있습니다.
현재 목록 항목이 원하는 기준을 충족하는 경우 새 목록을 만드는 것이 좋습니다.
그래서:
for item in originalList:
if (item != badValue):
newList.append(item)
새 목록 이름으로 전체 프로젝트를 다시 코딩하지 않아도됩니다.
originalList[:] = newList
파이썬 문서에서 참고하십시오 :
copy.copy (x) x의 얕은 복사본을 반환합니다.
copy.deepcopy (x) x의 깊은 사본을 반환합니다.
이 답변은 원래 중복으로 표시 된 질문에 대한 답변으로 작성되었습니다 .python의 목록에서 좌표 제거
코드에는 두 가지 문제가 있습니다.
1) remove ()를 사용할 때 정수를 제거하려고 시도하지만 튜플을 제거해야합니다.
2) for 루프는 목록의 항목을 건너 뜁니다.
코드를 실행할 때 어떤 일이 발생하는지 살펴 보겠습니다.
>>> 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)
첫 번째 문제는 remove ()에 'a'와 'b'를 모두 전달하지만 remove ()는 단일 인수 만 허용한다는 것입니다. 그렇다면 목록에서 제대로 작동하도록 remove ()를 어떻게 얻을 수 있습니까? 리스트의 각 요소가 무엇인지 파악해야합니다. 이 경우, 각각은 튜플입니다. 이를 확인하려면 목록의 한 요소에 액세스하십시오 (인덱싱은 0에서 시작).
>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>
아하! L1의 각 요소는 실제로 튜플입니다. 이것이 바로 remove ()에 전달해야하는 것입니다. 파이썬의 튜플은 매우 쉽습니다. 간단히 괄호 안에 값을 넣는 것입니다. "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를 만들 때 파이썬이 실제로 새 객체를 만들지 않았기 때문입니다. 대신, L1을 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'오브젝트를 리턴합니다. 실용적인 목적으로, 당신은 그것의 주장의 역전 된 사본을 만드는 것으로 생각할 수 있습니다. 이것이 내가 권장하는 솔루션입니다.
반복하는 동안 다른 작업을 수행하려면 색인 (예를 들어 dict 목록이있는 경우 색인을 참조 할 수 있음)과 실제 목록 항목 컨텐츠를 모두 얻는 것이 좋습니다.
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()
기본 제공으로 사용 가능할 수 있습니다 .
자세한 내용은 여기를 확인하십시오
for-looping을 반대로 시도하면 some_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)
이렇게하면 인덱스가 정렬되고 목록 요소가 발생하지 않더라도 목록 업데이트가 발생하지 않습니다.
reversed(list(enumerate(some_list)))
는 자신을 계산하는 것보다 간단합니다.
하나의 가능한 해결책은 일부를 제거 할뿐만 아니라 단일 루프에서 모든 요소로 무언가를 수행하려는 경우에 유용합니다.
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
bad
물건 을 제거 하고, 그것을 가지고 무언가를하고 또한 good
하나의 루프에서 물건으로 무언가를 하고 싶다면 어떻게해야 합니까?
alist[:]
. 좋은 개정이 좋습니다. 공감하십시오.
비슷한 일을해야했고 내 경우에는 문제가 메모리였습니다. 목록에 여러 데이터 세트 객체를 병합 한 다음 새 객체로 사용하고 병합하려는 각 항목을 제거해야했습니다. 그들 모두를 복제하고 메모리를 폭파시키지 마십시오. 필자의 경우 목록 대신 사전에 객체를 갖는 것이 잘 작동했습니다.
```
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'
가능하면 반복 가능한 동안 iterable을 수정하지 않아도되는 다른 방법을 사용하는 것이 가장 좋지만 일부 알고리즘의 경우에는 그다지 간단하지 않을 수 있습니다. 따라서 원래 질문에 설명 된 코드 패턴을 정말로 원한다면 가능할 수 있습니다.
목록뿐만 아니라 모든 가변 시퀀스에서 작동합니다.
전체 답변 :
편집 :이 답변의 마지막 코드 예제 는 목록 이해를 사용하지 않고 대신 목록을 수정하려는 이유에 대한 사용 사례를 제공합니다 . 답변의 첫 부분은 배열 을 어떻게 수정 하는 지에 대한 자습서 역할을 합니다 .
해결책 은 senderle 의이 답변 (관련 질문에 대한)에서 따릅니다. 배열 목록이 수정 된 목록을 반복하면서 업데이트되는 방법을 설명합니다. 아래 솔루션은 목록이 수정 된 경우에도 배열 인덱스를 올바르게 추적하도록 설계되었습니다.
다운로드 fluidIter.py
에서 여기 https://github.com/alanbacon/FluidIterator
필요가 자식을 설치하지 않을 수 있도록, 그것은 단지 하나의 파일입니다. 설치 프로그램이 없으므로 파일이 파이썬 경로에 있는지 확인해야합니다. 이 코드는 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 루프에서 동일한 iterable을 사용하고 수정합니다.
처음부터 언급했듯이 : 이것은 코드의 가독성을 손상시키고 디버그하기가 더 어려운 복잡한 솔루션입니다. 따라서 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]
some_list[:] = [x for x in some_list if not some_condition(x)]
없는 것은 무엇입니까? 이에 대한 답이 없으면 왜 600 줄 라이브러리를 다운로드하여 사용하는 것이 오타와 주석 처리 된 코드로 완성되는 것이 원 라이너보다 문제에 대한 더 나은 해결책이라고 생각해야합니까? -1.
some_list[:] = [x for x in some_list if not some_condition(y)]
곳 과 같은 것을 작성할 수 없습니다 . 쓰기도 불가능하다 . y
x
some_list[:] = [x for x in some_list if not some_condition(intermediateStateOf_some_list)]
가장 효과적인 방법은 목록 이해입니다. 많은 사람들이 자신의 사례를 보여줍니다. 물론 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]
주의 : 반복자를 처리 할 수도 없습니다. 반복자는 때때로 시퀀스보다 낫습니다.
for 루프는 인덱스를 반복합니다.
목록이 있다고 생각해
[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
그래서 네 번째 반복 완료 포인터가 다섯 번째로 이동했습니다.
그렇기 때문에 루프가 이전 인덱스로 이동 한 이후 루프가 65를 커버하지 않는 이유는 무엇입니까?
따라서 복사 대신 원본을 여전히 참조하는 다른 변수로 목록을 참조해서는 안됩니다.
ite = lis #dont do it will reference instead copy
그래서 목록의 사본을 사용하여 list[::]
지금 당신은 그것을 줄 것이다
[5, 7, 13, 29]
문제는 반복하는 동안 목록에서 값을 제거하면 목록 색인이 축소되는 것입니다.
대신 이해력을 시험해 볼 수 있습니다.
목록, 튜플, dict, 문자열 등 모든 반복 가능을 지원합니다.
다른 답변은 반복하는 목록에서 일반적으로 삭제하는 것이 좋지 않다는 것이 맞습니다. 역 반복은 함정을 피하지만 코드를 따르는 것은 훨씬 어렵 기 때문에 일반적으로 목록 이해 또는를 사용하는 것이 좋습니다 filter
.
그러나 반복하는 시퀀스에서 요소를 제거하는 것이 안전한 경우가 있습니다. 반복하는 동안 하나의 항목 만 제거하는 경우입니다. a return
또는 a를 사용하여 보장 할 수 있습니다 break
. 예를 들면 다음과 같습니다.
for i, item in enumerate(lst):
if item % 4 == 0:
foo(item)
del lst[i]
break
어떤 조건을 만족하는 목록의 첫 번째 항목에 부작용이있는 작업을 수행 한 후 바로 목록에서 해당 항목을 제거 할 때 목록 이해보다 이해하기가 더 쉽습니다.
문제를 해결하기위한 세 가지 접근 방식을 생각할 수 있습니다. 예를 들어 임의의 튜플 목록을 만듭니다 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 루프 안에 코드를 채우는 곳). 나는 작은 코드를 사용 del
하여 상기 조건에 맞는 튜플을 삭제합니다. 그러나, 연속적으로 배치 된 2 개의 튜플이 주어진 조건을 만족시키는 경우,이 방법은 (상기 조건을 만족하는) 튜플을 놓칠 것이다.
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보다 빠릅니다 . Method2와 method3은 method1보다 효율적입니다. 나는 method2 선호한다 . 전술 한 예에서,time(method1) : time(method2) : time(method3) = 1 : 1 : 1.7
정말로 큰 잠재력을 가진 것은 다음을 사용합니다.
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
숫자 목록을 세우고 3으로 나눌 수있는 모든 no를 제거하려고합니다.
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)