development

목록에서 여러 요소 삭제

big-blog 2020. 6. 22. 07:20
반응형

목록에서 여러 요소 삭제


목록에서 여러 요소를 동시에 삭제할 수 있습니까? 인덱스 0과 2에서 요소를 삭제하고 del somelist [0], del somelist [2]와 같은 것을 시도하려면 두 번째 명령문이 실제로 somelist [3]을 삭제합니다.

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


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

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

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

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

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

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

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

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


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

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

a[2:10] = []

기능으로서 :

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

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


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

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

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


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, 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.


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

SomeList = [1,2,3,4,5,6,7,8,10]
Rem = [0,5,7]

for i in Rem:
    SomeList[i]='!' # mark for deletion

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

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

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


여기 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].


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

>>> 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

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

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']

이것은 언급되었지만 어쨌든 아무도 실제로 그것을 제대로 얻지 못했습니다.

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

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

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


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 ()는 목록에서 중복 된 요소를 처리 할 수 ​​없으므로 사용하지 않는 것이 좋습니다.


제거 방법은 목록 요소를 많이 이동시킵니다. 나는 사본을 만드는 것이 낫다고 생각합니다.

...
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
...

technically, the answer is NO it is not possible to delete two objects AT THE SAME TIME. However, it IS possible to delete two objects in one line of beautiful python.

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

will recusrively delete foo['bar'], then foo['baz']


we can do this by use of a for loop iterating over the indexes after sorting the index list in descending order

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

For the indices 0 and 2 from listA:

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

For some random indices to remove from listA:

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

I wanted to a way to compare the different solutions that made it easy to turn the knobs.

First I generated my data:

import random

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

Then I defined my functions:

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)

Then I used timeit to compare the solutions:

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)

Output

set =   1.711
del =   3.450
pop =   3.618

So the generator with the indices in a set was the winner. And del is slightly faster then pop.


You can use this logic:

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

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

print c

I can actually think of two ways to do it:

  1. slice the list like (this deletes the 1st,3rd and 8th elements)

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

  2. do that in place, but one at a time:

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


You can do that way on a dict, not on a list. In a list elements are in sequence. In a dict they depend only on the index.

Simple code just to explain it by doing:

>>> 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'

A way to "convert" a list in a dict is:

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

The inverse is:

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

Anyway I think it's better to start deleting from the higher index as you said.


To generalize the comment from @sth. Item deletion in any class, that implements abc.MutableSequence, and in list in particular, is done via __delitem__ magic method. This method works similar to __getitem__, meaning it can accept either an integer or a slice. Here is an example:

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)

This will output

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

Importing it only for this reason might be overkill, but if you happen to be using pandas anyway, then the solution is simple and straightforward:

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']

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

Avoids sorting cost and having to explicitly copy list.


Another implementation of the idea of removing from the highest index.

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

How about one of these (I'm very new to Python, but they seem ok):

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)

['Atlantic', 'Pacific', 'Indian']

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)

['Atlantic', 'Pacific', 'Indian']

참고URL : https://stackoverflow.com/questions/497426/deleting-multiple-elements-from-a-list

반응형