목록에서 여러 요소 삭제


160

목록에서 여러 요소를 동시에 삭제할 수 있습니까? 인덱스 0과 2에서 요소를 삭제하고 del somelist[0], 그 뒤에 다음 과 같이 시도 del somelist[2]하면 두 번째 문이 실제로 삭제 somelist[3]됩니다.

나는 항상 높은 번호의 요소를 먼저 삭제할 수 있다고 생각하지만 더 좋은 방법이 있기를 바랍니다.

답변:


110

이 문제에 대한 최상의 해결책은 아닐 것입니다.

indices = 0, 2
somelist = [i for j, i in enumerate(somelist) if j not in indices]

2
거의 전체 목록을 삭제 한 경우에만 가능합니다. len (indices) * len (somelist)입니다. 또한 원할 수도 있고 원하지 않을 수도있는 사본을 만듭니다.
Richard Levasseur

목록에서 값을 확인하는 경우입니다. 'in'연산자는 목록의 값에서 작동하지만 dict의 키에서는 작동합니다. 내가 틀렸다면, pep / reference를 알려주십시오
Richard Levasseur

5
내가 인덱스를 위해 튜플을 선택한 이유는 기록의 단순성뿐이었습니다. 그것은 set ()이 O (n)을주는 완벽한 일이 될 것입니다
SilentGhost

18
이것은 일부 목록에서 항목을 전혀 삭제하는 것이 아니라 새로운 목록을 만드는 것입니다. 원본 목록에 대한 참조를 보유한 항목이 있으면 여전히 모든 항목이 포함됩니다.
Tom Future

2
@SilentGhost 열거 할 필요는 없습니다. 이건 somelist = [ lst[i] for i in xrange(len(lst)) if i not in set(indices) ]어때?
ToolmakerSteve

183

어떤 이유로 나는 여기에 대답이 마음에 들지 않습니다. 예, 작동하지만 엄밀히 말하면 대부분 목록에서 요소를 삭제하지는 않습니까? (그러나 사본을 만든 다음 원본을 편집 된 사본으로 바꾸십시오).

왜 더 높은 색인을 먼저 삭제하지 않습니까?

이것에 대한 이유가 있습니까? 나는 단지 할 것이다 :

for i in sorted(indices, reverse=True):
    del somelist[i]

항목을 뒤로 삭제하지 않으려면 마지막으로 삭제 된 색인보다 큰 색인 값을 줄이거 나 (다른 목록을 가지고 있기 때문에 실제로 동일한 색인을 사용할 수는 없음) 추측해야합니다 목록의 사본 ( '삭제'하지 않고 원본을 편집 된 사본으로 대체)

역순으로 삭제하지 않는 이유가 있습니까?


1
이것이 왜 대답으로 선택되지 않았는지 모르겠습니다!. 고마워
swathis

4
두 가지 이유가 있습니다. (a) 목록의 경우, 일부 요소는 여러 번 앞으로 이동해야하므로 시간 복잡도는 평균적으로 (임의 인덱스를 사용하여) "복사본 만들기"방법 (인덱스 세트 사용)보다 높습니다. (b) 적어도 실제 프로그램 논리에 해당하지 않고 기술적 인 이유로 만 존재하는 정렬 함수가 있기 때문에 읽기가 어렵습니다. 지금까지 나는 이미 그 논리를 철저히 이해하고 있지만 여전히 읽기가 어렵다고 생각 합니다.
Imperishable Night

1
@ImperishableNightclaborate 할 수 있습니까? "일부 요소를 변경해야합니다"를 이해하지 못합니다. (b)의 경우 명확성을 읽으려면 함수를 정의하면됩니다.
tglaria

109

인접하지 않은 여러 항목을 삭제하는 경우 설명하는 것이 가장 좋습니다 (그렇습니다. 가장 높은 색인에서 시작하십시오).

아이템이 인접한 경우 슬라이스 할당 구문을 사용할 수 있습니다.

a[2:10] = []

95
del a[2:10]같은 효과로 말할 수도 있습니다 .
sth

8
@sth 흥미롭게도 델은 할당하는 것보다 조금 빠릅니다.
thefourtheye

24

numpy.delete다음과 같이 사용할 수 있습니다 .

import numpy as np
a = ['a', 'l', 3.14, 42, 'u']
I = [0, 2]
np.delete(a, I).tolist()
# Returns: ['l', '42', 'u']

마지막에 numpy배열로 끝나는 것이 마음에 들지 않으면를 생략하십시오 .tolist(). 속도가 상당히 향상되어 확장 성이 뛰어난 솔루션이 될 것입니다. 벤치마킹하지는 않았지만 numpy작업은 C 또는 Fortran으로 작성된 코드로 컴파일됩니다.


1
요소가 연속적이지 않을 때의 일반적인 해결책 +1
noɥʇʎԀʎzɐɹƆ

1
질문은 여기에서 어떻게 삭제 하는가 [ 'a', 42].
evanhutomo

이 솔루션의 다른 보너스 포인트에 비해 큰 보너스 포인트가 제공됩니다. 내가 말할 수있는 것은 매우 큰 데이터 세트의 경우 몇 초 만에 좋은 결과를 얻는 데 몇 분이 걸렸다는 것입니다.
legel

18

Greg의 답변을 전문으로 확장 슬라이스 구문을 사용할 수도 있습니다. 예. 항목 0과 2를 삭제하려는 경우

>>> a= [0, 1, 2, 3, 4]
>>> del a[0:3:2]
>>> a
[1, 3, 4]

이것은 물론 임의의 선택을 다루지는 않지만 두 항목을 삭제하는 데 확실히 작동 할 수 있습니다.


16

기능으로서 :

def multi_delete(list_, *args):
    indexes = sorted(list(args), reverse=True)
    for index in indexes:
        del list_[index]
    return list_

n log (n) 시간 내에 실행 되므로 아직 가장 빠른 올바른 솔루션이되어야합니다.


1
args.sort (). reverse ()가있는 버전이 더 좋습니다. 또한 던지거나 더 나쁘게 조용히 손상시키는 대신 dicts와 함께 작동합니다.

sort ()는 튜플에 대해 정의되어 있지 않으므로 먼저 목록으로 변환해야합니다. sort ()는 None을 반환하므로 reverse ()를 사용할 수 없습니다.
SilentGhost

@ R. Pate : 그런 이유로 첫 번째 버전을 제거했습니다. 감사. @ SilentGhost : 고쳤습니다.
Nikhil Chelliah

@Nikhil : 아니요;; args = list (args) args.sort () args.reverse () 그러나 더 나은 옵션은 다음과 같습니다. args = sorted (args, reverse = True)
SilentGhost

2
n log n? 정말? 나는 del list[index]O (1) 라고 생각하지 않습니다 .
user202729

12

따라서 한 번에 여러 요소를 삭제하고 싶습니까? 이 경우 삭제할 다음 요소의 위치는 이전에 삭제 된 많은 요소에 의해 오프셋됩니다.

우리의 목표는 인덱스 1, 4 및 7로 미리 계산 된 모든 모음을 삭제하는 것입니다. to_delete 인덱스는 오름차순으로되어 있어야합니다. 그렇지 않으면 작동하지 않습니다.

to_delete = [1, 4, 7]
target = list("hello world")
for offset, index in enumerate(to_delete):
  index -= offset
  del target[index]

어떤 순서로든 요소를 ​​삭제하려면 더 복잡합니다. IMO, to_delete에서 빼거나 ​​빼야 할 때를 알아내는 것보다 정렬 이 더 쉬울 수 있습니다 index.


8

나는 파이썬의 초보자입니다. 지금은 프로그래밍이 거칠고 지저분하지만, 내 솔루션은 초기 자습서에서 배운 기본 명령의 조합을 사용하는 것이 었습니다.

some_list = [1,2,3,4,5,6,7,8,10]
rem = [0,5,7]

for i in rem:
    some_list[i] = '!' # mark for deletion

for i in range(0, some_list.count('!')):
    some_list.remove('!') # remove
print some_list

분명히 "삭제 표시"문자를 선택해야하기 때문에 여기에는 한계가 있습니다.

목록의 크기가 확장 될 때의 성능에 관해서는 솔루션이 차선책이라고 확신합니다. 그러나 그것은 간단합니다. 다른 초보자들에게 호소하기를 바랍니다 some_list. 잘 알려진 형식 (예 : 항상 숫자) 인 간단한 경우에 작동 합니다 ...


2
사용하는 대신 '!' 당신의 특별한 캐릭터로, None을 사용하십시오. 이것은 모든 문자를 유효하게 유지하고 당신의 가능성을 해방합니다
portforwardpodcast

5

다음은 SilentGhost의 원래 답변과 같이 enumerate ()를 사용하여 튜플을 생성하지 않는 대안입니다.

이것은 나에게 더 읽기 쉬운 것 같습니다. 열거 형을 사용하는 습관이 있다면 다르게 느낄 수도 있습니다.주의 사항 : 두 가지 접근 방식의 성능을 테스트하지 않았습니다.

# Returns a new list. "lst" is not modified.
def delete_by_indices(lst, indices):
    indices_as_set = set(indices)
    return [ lst[i] for i in xrange(len(lst)) if i not in indices_as_set ]

참고 : Python 2.7 구문. Python 3의 경우 xrange=> range.

용법:

lst = [ 11*x for x in xrange(10) ]
somelist = delete_by_indices( lst, [0, 4, 5])

somelist :

[11, 22, 33, 66, 77, 88, 99]

--- 보너스 ---

목록에서 여러 값을 삭제하십시오. 즉, 삭제하려는 값이 있습니다.

# Returns a new list. "lst" is not modified.
def delete__by_values(lst, values):
    values_as_set = set(values)
    return [ x for x in lst if x not in values_as_set ]

용법:

somelist = delete__by_values( lst, [0, 44, 55] )

somelist :

[11, 22, 33, 66, 77, 88, 99]

이것은 이전과 같은 대답이지만 이번에는 삭제할 VALUES를 제공했습니다 [0, 44, 55].


열거 형의 결과에 사용되는 비 설명 변수 이름으로 인해 @ SilentGhost 's를 읽기가 어려울 것이라고 결정했습니다. 또한, Parens는 읽기 쉬워 졌을 것입니다. 그래서 여기에 그의 해결책을 말한 방법이 있습니다 (성능을 위해 "set"이 추가됨) [ value for (i, value) in enumerate(lst) if i not in set(indices) ]. 그러나 값으로 삭제하는 방법도 보여주기 때문에 여기에 답을 남겨 두겠습니다. 더 쉬운 경우이지만 누군가를 도울 수 있습니다.
ToolmakerSteve

@ Veedrac- 감사합니다; 세트를 먼저 작성하기 위해 다시 작성했습니다. SilentGhost보다 빠른 솔루션은 무엇이라고 생각하십니까? (실제로 시간을 내서 의견을 묻는 것만으로는 충분하지 않다고 생각합니다.) 마찬가지로 SilentGhost의 버전을 indices_as_set = set(indices), 로 다시 작성 [ value for (i, value) in enumerate(lst) if i not in indices_as_set ]하여 속도를 높일 것입니다.
ToolmakerSteve

이중 밑줄에 대한 스타일 이유가 delete__by_values()있습니까?
Tom

5

리스트 인덱스 값을 사용하는 대체리스트 이해 방법 :

stuff = ['a', 'b', 'c', 'd', 'e', 'f', 'woof']
index = [0, 3, 6]
new = [i for i in stuff if stuff.index(i) not in index]

이것은 다음을 반환합니다.

['b', 'c', 'e', 'f']

좋은 대답이지만 index목록 반복자에서 방법을 사용하기 때문에 오해의 소지가있는 색인 목록의 이름을 지정합니다.index()
Joe

4

여기에 요소를 제거하는 또 다른 방법이 있습니다. 또한 목록이 정말 길면 더 빠릅니다.

>>> a = range(10)
>>> remove = [0,4,5]
>>> from collections import deque
>>> deque((list.pop(a, i) for i in sorted(remove, reverse=True)), maxlen=0)

>>> timeit.timeit('[i for j, i in enumerate(a) if j not in remove]', setup='import random;remove=[random.randrange(100000) for i in range(100)]; a = range(100000)', number=1)
0.1704120635986328

>>> timeit.timeit('deque((list.pop(a, i) for i in sorted(remove, reverse=True)), maxlen=0)', setup='from collections import deque;import random;remove=[random.randrange(100000) for i in range(100)]; a = range(100000)', number=1)
0.004853963851928711

+1 : "for .. :"블록을 요구하지 않고 표현의 일부로 동작을 수행하기 위해 deque를 흥미롭게 사용합니다. 그러나이 간단한 경우 Nikhil의 블록 읽기가 더 읽기 쉽습니다.
ToolmakerSteve

4

이것은 언급되었지만 어떻게 든 실제로 그것을 제대로 얻을 수는 없었습니다.

에에게 O(n)해결책은 다음과 같습니다

indices = {0, 2}
somelist = [i for j, i in enumerate(somelist) if j not in indices]

이것은 SilentGhost의 버전 과 거의 비슷하지만 두 개의 중괄호를 추가합니다.


각 반복에 O(n)걸리는 조회를 계산하는 경우 에는 그렇지 않습니다 log(len(indices)).
Mad Physicist

@MadPhysicist j not in indicesO(1)입니다.
Veedrac

그 번호를 어떻게 얻었는지 잘 모르겠습니다. 인덱스는 세트이므로 j not in indices여전히 조회가 필요합니다 O(log(len(indices))). 2- 요소 집합의 조회는 다음과 같은 자격이있는 것에 동의하지만 O(1)일반적인 경우에는 다음과 같습니다 O(log(N)). 어느 쪽이든 O(N log(N))여전히 이길 수 O(N^2)있습니다.
Mad Physicist


그리고 두 개의 버팀대는 정확히 무엇을 했습니까?
Nuclear03020704

4
l = ['a','b','a','c','a','d']
to_remove = [1, 3]
[l[i] for i in range(0, len(l)) if i not in to_remove])

기본적으로 최고 투표 답변과 동일하며 다른 방식으로 작성합니다. l.index ()는 목록에서 중복 된 요소를 처리 할 수 ​​없으므로 사용하지 않는 것이 좋습니다.


2

메소드를 제거하면 목록 요소가 많이 이동합니다. 나는 사본을 만드는 것이 낫다고 생각합니다.

...
new_list = []
for el in obj.my_list:
   if condition_is_true(el):
      new_list.append(el)
del obj.my_list
obj.my_list = new_list
...

2

기술적으로 대답은 아니요입니다. 같은 시간에 두 개체를 삭제할 수 없습니다. 그러나 한 줄의 아름다운 파이썬에서 두 개의 객체를 삭제할 수 있습니다.

del (foo['bar'],foo['baz'])

recusrively 삭제 foo['bar']한 다음foo['baz']


이것은 목록이 아닌 dict 객체에서 삭제되지만 여전히 +1하고 있습니다.
Ulf Aslak

적절한 구문으로 list에도 적용됩니다. 그러나 동시에 두 개체를 삭제할 수 없다는 주장은 거짓입니다. 의해 답변을 @bobince
Pedro Gimeno

2

인덱스 목록을 내림차순으로 정렬 한 후 인덱스를 반복하는 for 루프를 사용하여이를 수행 할 수 있습니다.

mylist=[66.25, 333, 1, 4, 6, 7, 8, 56, 8769, 65]
indexes = 4,6
indexes = sorted(indexes, reverse=True)
for i in index:
    mylist.pop(i)
print mylist

2

listA의 인덱스 0과 2의 경우 :

for x in (2,0): listA.pop(x)

listA에서 일부 임의의 인덱스를 제거하려면 :

indices=(5,3,2,7,0) 
for x in sorted(indices)[::-1]: listA.pop(x)

2

노브를 돌리기 쉽게하는 여러 가지 솔루션을 비교하는 방법을 원했습니다.

먼저 내 데이터를 생성했습니다.

import random

N = 16 * 1024
x = range(N)
random.shuffle(x)
y = random.sample(range(N), N / 10)

그런 다음 내 기능을 정의했습니다.

def list_set(value_list, index_list):
    index_list = set(index_list)
    result = [value for index, value in enumerate(value_list) if index not in index_list]
    return result

def list_del(value_list, index_list):
    for index in sorted(index_list, reverse=True):
        del(value_list[index])

def list_pop(value_list, index_list):
    for index in sorted(index_list, reverse=True):
        value_list.pop(index)

그런 다음 timeit솔루션을 비교하는 데 사용 했습니다.

import timeit
from collections import OrderedDict

M = 1000
setup = 'from __main__ import x, y, list_set, list_del, list_pop'
statement_dict = OrderedDict([
    ('overhead',  'a = x[:]'),
    ('set', 'a = x[:]; list_set(a, y)'),
    ('del', 'a = x[:]; list_del(a, y)'),
    ('pop', 'a = x[:]; list_pop(a, y)'),
])

overhead = None
result_dict = OrderedDict()
for name, statement in statement_dict.iteritems():
    result = timeit.timeit(statement, number=M, setup=setup)
    if overhead is None:
        overhead = result
    else:
        result = result - overhead
        result_dict[name] = result

for name, result in result_dict.iteritems():
    print "%s = %7.3f" % (name, result)

산출

set =   1.711
del =   3.450
pop =   3.618

따라서 지수가있는 발전기가 set승자가되었습니다. 그리고 del약간 빠릅니다 pop.


이 비교에 감사드립니다. 이로 인해 직접 테스트 (실제로 코드를 빌려 왔습니다)와 적은 수의 항목을 제거해야했습니다 .SET을 만들기위한 오버 헤드로 인해 최악의 솔루션이되었습니다 (10, 100, 500 사용) 'y'의 길이가 표시됩니다). 대부분의 경우 응용 프로그램에 따라 다릅니다.
tglaria

2

이 논리를 사용할 수 있습니다 :

my_list = ['word','yes','no','nice']

c=[b for i,b in enumerate(my_list) if not i in (0,2,3)]

print c

2

최고 지수에서 제거하려는 아이디어의 또 다른 구현.

for i in range(len(yourlist)-1, -1, -1):
    del yourlist(i)

1

실제로 두 가지 방법을 생각할 수 있습니다.

  1. 목록을 슬라이스하십시오 (이것은 1, 3 및 8 번째 요소를 삭제합니다)

    somelist = somelist [1 : 2] + somelist [3 : 7] + somelist [8 :]

  2. 한 번에 하나씩 그 위치에서 수행하십시오.

    somelist.pop (2) somelist.pop (0)


1

목록이 아닌 dict에서 그렇게 할 수 있습니다. 목록에서 요소는 순서대로 있습니다. dict에서 그들은 인덱스에만 의존합니다.

간단한 코드는 다음을 수행 하여 설명합니다 .

>>> lst = ['a','b','c']
>>> dct = {0: 'a', 1: 'b', 2:'c'}
>>> lst[0]
'a'
>>> dct[0]
'a'
>>> del lst[0]
>>> del dct[0]
>>> lst[0]
'b'
>>> dct[0]
Traceback (most recent call last):
  File "<pyshell#19>", line 1, in <module>
    dct[0]
KeyError: 0
>>> dct[1]
'b'
>>> lst[1]
'c'

dict에서 목록을 "변환"하는 방법은 다음과 같습니다.

>>> dct = {}
>>> for i in xrange(0,len(lst)): dct[i] = lst[i]

그 반대는 다음과 같습니다.

lst = [dct[i] for i in sorted(dct.keys())] 

어쨌든 나는 당신이 말한 것처럼 더 높은 색인에서 삭제를 시작하는 것이 낫다고 생각합니다.


파이썬은 [dct에서 i에 대한 dct [i]가 항상 증가하는 i 값을 사용할 것이라고 보장합니까? 그렇다면 list (dct.values ​​())가 더 좋습니다.

나는 그것에 대해 생각하지 않았다. 네가 옳아. [here] [1]을 (를) 읽었을 때 품목이 순서대로 또는 적어도 예상되는 순서로 선택 될 것이라는 보장은 없습니다. 편집했습니다. [1] : docs.python.org/library/stdtypes.html#dict.items
Andrea Ambu

2
이 답변은 기본적으로 잘못된 방식으로 사전에 대해 이야기합니다. 사전에는 KEYS (INDICES 아님)가 있습니다. 예, 키 / 값 쌍은 서로 독립적입니다. 아니요, 항목을 삭제하는 순서는 중요하지 않습니다. 목록에서 일부 요소를 삭제하기 위해 사전으로 변환하면 과도합니다.
ToolmakerSteve

1

@sth 의 주석을 일반화합니다 . 구현이 그 모든 클래스에서 항목 삭제, abc.MutableSequence , 그리고에 list특히,을 통해 이루어집니다 __delitem__마술 방법. 이 방법은와 비슷하게 작동합니다 __getitem__. 즉, 정수 또는 슬라이스를 사용할 수 있습니다. 예를 들면 다음과 같습니다.

class MyList(list):
    def __delitem__(self, item):
        if isinstance(item, slice):
            for i in range(*item.indices(len(self))):
                self[i] = 'null'
        else:
            self[item] = 'null'


l = MyList(range(10))
print(l)
del l[5:8]
print(l)

출력됩니다

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 'null', 'null', 'null', 8, 9]

1

이러한 이유로 만 가져 오는 것은 과도 할 수 있지만 pandas어쨌든 사용 하는 경우 솔루션은 간단하고 간단합니다.

import pandas as pd
stuff = pd.Series(['a','b','a','c','a','d'])
less_stuff = stuff[stuff != 'a']  # define any condition here
# results ['b','c','d']

1
some_list.remove(some_list[max(i, j)])

정렬 비용과 명시 적으로 목록을 복사하지 않아도됩니다.


0

이 중 하나는 어떻습니까 (파이썬을 처음 접했지만 괜찮아 보입니다 ).

ocean_basin = ['a', 'Atlantic', 'Pacific', 'Indian', 'a', 'a', 'a']
for i in range(1, (ocean_basin.count('a') + 1)):
    ocean_basin.remove('a')
print(ocean_basin)

[ '대서양', '태평양', '인도']

ob = ['a', 'b', 4, 5,'Atlantic', 'Pacific', 'Indian', 'a', 'a', 4, 'a']
remove = ('a', 'b', 4, 5)
ob = [i for i in ob if i not in (remove)]
print(ob)

[ '대서양', '태평양', '인도']


0

지금까지 제안 된 답변 중에 삭제 수행하지 않습니다 장소에서 삭제할 인덱스의 임의의 수의리스트의 길이에 O (N)에서를, 그래서 여기 내 버전입니다 :

def multi_delete(the_list, indices):
    assert type(indices) in {set, frozenset}, "indices must be a set or frozenset"
    offset = 0
    for i in range(len(the_list)):
        if i in indices:
            offset += 1
        elif offset:
            the_list[i - offset] = the_list[i]
    if offset:
        del the_list[-offset:]

# Example:
a = [0, 1, 2, 3, 4, 5, 6, 7]
multi_delete(a, {1, 2, 4, 6, 7})
print(a)  # prints [0, 3, 5]

0

remove도 사용할 수 있습니다.

delete_from_somelist = []
for i in [int(0), int(2)]:
     delete_from_somelist.append(somelist[i])
for j in delete_from_somelist:
     newlist = somelist.remove(j)

0

list_diff첫 번째 목록의 원래 순서를 유지하면서 단순히 두 목록을 입력으로 가져 와서 그 차이를 반환 하는 함수에 모두 넣었습니다 .

def list_diff(list_a, list_b, verbose=False):

    # returns a difference of list_a and list_b,
    # preserving the original order, unlike set-based solutions

    # get indices of elements to be excluded from list_a
    excl_ind = [i for i, x in enumerate(list_a) if x in list_b]
    if verbose:
        print(excl_ind)

    # filter out the excluded indices, producing a new list 
    new_list = [i for i in list_a if list_a.index(i) not in excl_ind]
    if verbose:
        print(new_list)

    return(new_list)

샘플 사용법 :

my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'woof']
# index = [0, 3, 6]

# define excluded names list
excl_names_list = ['woof', 'c']

list_diff(my_list, excl_names_list)
>> ['a', 'b', 'd', 'e', 'f']
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.