우아한 방법으로 항목을 제거하에서 시퀀스에서는 파이썬?[중복]
-
09-06-2019 - |
문제
이 질문은 이미 있는 대답을 여기:
내가 쓰는 코드 라이브러리는 모두 지원되며,내가 종종 필요한 항목을 제거하는 목록에서 또는 다른 시퀀스 입력에 따라 기준입니다.지 못한 해결책을 발견되는 우아하고 효율적으로 항목을 제거하는 목록에서 현재 반복은 나쁜 것입니다.예를 들어,이 작업을 할 수 없습니다:
for name in names:
if name[-5:] == 'Smith':
names.remove(name)
나는 일반적으로 끝나 뭔가를 하는 다음과 같다:
toremove = []
for name in names:
if name[-5:] == 'Smith':
toremove.append(name)
for name in toremove:
names.remove(name)
del toremove
이 innefficient,상당히 추하고 가능하게 버그(어떻게 여러 개를 처리할 수 있는'존 스미스'항목?).누군가가 더 우아한 솔루션으로,또는 적어도 더 효율적으로 하나?
는 방법에 대해 중 하나는 작품으로도 할 수 있습니다.
해결책
두 쉽게 달성하는 방법에만 필터링되:
용
filter
:names = filter(lambda name: name[-5:] != "Smith", names)
를 사용하여 목록을 함축:
names = [name for name in names if name[-5:] != "Smith"]
참고는 모두의 경우 값을 유지하는 조건자의 기능을 평가하여 True
, 는,그래서 당신은 반대로 논리(즉당신이 말하는"지키지 않는 사람들이 마지막 이름 Smith"대신에"제거하는 사람들 마지막 이름 Smith").
편집 재미있는...두 사람이 개별적으로 게시 모두의 답변을 제안했으로 나가 게시 광산이다.
다른 팁
할 수도 있습니다 반복하여 거꾸로 위 목록:
for name in reversed(names):
if name[-5:] == 'Smith':
names.remove(name)
이는 장점을 가지고 있는 만들어지지 않습니다 새로운 목록(아 filter
또는 목록의 이해)사용 반복기 대신의 목록 사본(아 [:]
).
참고 하지만 요소를 제거하는 동안 반복 뒤로 안전 삽입하는 그들은 다소 난이도합니다.
분명한 대답을 하는 요한과 몇 가지 다른 사람들,즉:
>>> names = [name for name in names if name[-5:] != "Smith"] # <-- slower
하지만 그는 단점이 있다 새로 만들고 목록의 개체,보다는 오히려 다시 사용하면 원래 개체.나는 몇 가지 프로파일링 및 실험,그리고 가장 효율적인 방법이 나온다:
>>> names[:] = (name for name in names if name[-5:] != "Smith") # <-- faster
에 할당"이름:]"기본적으로 의미"의 내용을 대체하기에 이름 목록 다음과 같은 가치".그것이터 할당을 이름에는 그것이 만들어지지 않습니다 새로운 목록 개체입니다.의 오른쪽에 할당 발전기 식(주 괄호를 사용하여 보다는 오히려 대괄호).이 Python 을 반복하러 목록입니다.
일부는 빠른 프로파일링을 제안이 약 30%보다 더 빨리 목록이 이해에 접근,그리고 약 40%더 빠르게 필터 접근 방식이다.
주의:이 솔루션을 보다 빠르게 확실한 해결책,그것은 더 어둡고에 의존하여 더 많은 고급 Python 기술입니다.당신이 그것을 사용하는 경우에,나는 추천 동반으로합니다.그것은 아마만 사용할 가치가 있는 경우에 당신은 당신이 정말로 걱정하의 성능이 특정 작업(는 매우 빨리 상관 없이).(경우에는 내가 사용하는 이,리*빔 검색 및 사용 이를 제거하는 지점 검색에서 검색 빔입니다.)
용 목록 이해
list = [x for x in list if x[-5:] != "smith"]
거기에 시간 경우 필터링(필터를 사용하거나 또는 목록의 이해)작동하지 않습니다.이 때 발생하는 몇 가지 다른 객체에 대한 참조 목록에 당신을 수정하고 수정할 필요가 있 목록에서 장소입니다.
for name in names[:]:
if name[-5:] == 'Smith':
names.remove(name)
유일한 차이의 원래 코드의 사용 names[:]
대 names
에 대한 반복입니다.는 방법으로드 반복하는(얕은)목록의 사본을하고 제거가 정상적으로 작동합니다.이 목록에 복사하는 얕은,그것은 매우 빠르다.
필터가 될 것이 굉장하다.간단한 예제:
names = ['mike', 'dave', 'jim']
filter(lambda x: x != 'mike', names)
['dave', 'jim']
편집: 코리의 목록을 이해력을 구축 할 수 있습니다..
names = filter(lambda x: x[-5:] != "Smith", names);
모두 솔루션 필터 고 이해 필요한 건물은 새로운 목록입니다.나는 알 수 없는 충분한의 내부를 확인하기 위해,그러나 나 생각 는 전통적인(지만 우아한)접근할 수 있는 더 효율적인:
names = ['Jones', 'Vai', 'Smith', 'Perez']
item = 0
while item <> len(names):
name = names [item]
if name=='Smith':
names.remove(name)
else:
item += 1
print names
어쨌든 짧은 목록에,나는 하나의 두 가지 솔루션을 제안했다.
귀하의 질문에 대답을 작업에 대한 사전 주의 해야 한 Python3.0 이 포함됩 dict 함축:
>>> {i : chr(65+i) for i in range(4)}
말은 시간에,당신이 할 수 있는 준 dict 이해 이 방법:
>>> dict([(i, chr(65+i)) for i in range(4)])
또는 더 직접적인 응답:
dict([(key, name) for key, name in some_dictionary.iteritems if name[-5:] != 'Smith'])
는 경우 목록 해야 될 필터링에서는 이러한 목록의 크기는 매우 크고,다음 알고리즘에서 언급된 이전 답변을 기반으로 목록입니다.remove()적합하지 않기 때문에,자신의 계산적 복잡도 O(n^2).이 경우에는 사용할 수 있습니다 다음과 같은 없다-그래서 pythonic 기능:
def filter_inplace(func, original_list):
""" Filters the original_list in-place.
Removes elements from the original_list for which func() returns False.
Algrithm's computational complexity is O(N), where N is the size
of the original_list.
"""
# Compact the list in-place.
new_list_size = 0
for item in original_list:
if func(item):
original_list[new_list_size] = item
new_list_size += 1
# Remove trailing items from the list.
tail_size = len(original_list) - new_list_size
while tail_size:
original_list.pop()
tail_size -= 1
a = [1, 2, 3, 4, 5, 6, 7]
# Remove even numbers from a in-place.
filter_inplace(lambda x: x & 1, a)
# Prints [1, 3, 5, 7]
print a
편집:실제로,이 솔루션 https://stackoverflow.com/a/4639748/274937 우수한 광산 솔루션입니다.그것은 더 pythonic 고 빠르게 작동합니다.그래서,여기에 새로운 filter_inplace()구현:
def filter_inplace(func, original_list):
""" Filters the original_list inplace.
Removes elements from the original_list for which function returns False.
Algrithm's computational complexity is O(N), where N is the size
of the original_list.
"""
original_list[:] = [item for item in original_list if func(item)]
필터 목록을 함축하는 확인을 위해 예를 들어,하지만 그들 부부의 문제는:
- 그들은 복사본을 만들의 목록을 반환하고 새로운 중 하나는 것입니다 비효율적이 될 때 원래의 목록은 정말 큰
- 그들은 정말이 될 수 있습니다 복잡할 때의 기준을 선택하는 항목에서(당신의 경우,이름[-5:]=='스미스')은 더 복잡하거나 여러 조건입니다.
원래의 솔루션은 실제로 더 효율적으로 아주 큰 나열하는 경우에도,우리 합의할 수 있는 그것의 추.하지만 경우에 당신을 걱정할 수 있는 여러 개 있는'존 스미스',그것에 의해 해결할 수 있습을 삭제하는 위치를 기반으로지에서 값:
names = ['Jones', 'Vai', 'Smith', 'Perez', 'Smith']
toremove = []
for pos, name in enumerate(names):
if name[-5:] == 'Smith':
toremove.append(pos)
for pos in sorted(toremove, reverse=True):
del(names[pos])
print names
우리가 선택할 수 없습니다 솔루션을 고려하지 않고 크기의 목록은,하지만 큰 목록이 나는 것을 선호하는 2-을 전달하는 대신 솔루션의 필터링하거나 함축 목록
의 경우에는 설정합니다.
toRemove = set([])
for item in mySet:
if item is unwelcome:
toRemove.add(item)
mySets = mySet - toRemove
여기에 나 filter_inplace
구현하는 데 사용할 수 있는 필터 목록에서 항목을 장소에,나는 내 자신이 독립적으로 찾기 전에 이 페이지로 이동합니다.그것은 동일한 알고리즘으로 무엇 PabloG 게시,그냥 보다 일반적인 사용할 수 있도록을 필터 목록을 장소에,그것은 또한 수에서 제거하는 기준으로 목록 comparisonFunc
는 경우 반대로 설정 True
;정렬의 역 필터는 경우에 당신은 것입니다.
def filter_inplace(conditionFunc, list, reversed=False):
index = 0
while index < len(list):
item = list[index]
shouldRemove = not conditionFunc(item)
if reversed: shouldRemove = not shouldRemove
if shouldRemove:
list.remove(item)
else:
index += 1
만,이것은 분명히 문제로 데이터 구조를 사용하고 있습니다.사용 hashtable 에 대한 예입니다.일부 구현을 지원하는 여러 항목을 키당,그래서 하나 pop 최신의 요소 또는 제거하 모니다.
그러나 이것은,그리고 당신이 무슨 솔루션을 찾을 수있는,우아함을 통해 서로 다른 데이터 구조,지 않는 알고리즘이 있습니다.어쩌면 당신은 더 잘 할 수 있다면 그것은 정렬하거나 무언가를하지만,반복 목록에 당신의 방법만 여기에.
편집: 중 하나가 깨닫는 그 요청의 효율성'...이러한 모든 제안된 방법만을 반복하는 목록은 동일한으로 그가 무엇을 권장합니다.