program tip

Python 목록에서 조건과 일치하는 처음 N 개 항목 제거

radiobox 2020. 12. 4. 08:04
반응형

Python 목록에서 조건과 일치하는 처음 N 개 항목 제거


함수가있는 경우 해당 조건과 일치하는 Python 목록에서 matchCondition(x)첫 번째 n항목을 제거하려면 어떻게 해야합니까?

한 가지 해결책은 각 항목을 반복하고 삭제 표시 (예 :로 설정 None) 한 다음 이해력으로 목록을 필터링하는 것입니다. 이렇게하려면 목록을 두 번 반복하고 데이터를 변경해야합니다. 이를 수행하는 더 관용적이거나 효율적인 방법이 있습니까?

n = 3

def condition(x):
    return x < 5

data = [1, 10, 2, 9, 3, 8, 4, 7]
out = do_remove(data, n, condition)
print(out)  # [10, 9, 8, 4, 7] (1, 2, and 3 are removed, 4 remains)

itertools.filterfalse사용하는 한 가지 방법 itertools.count:

from itertools import count, filterfalse

data = [1, 10, 2, 9, 3, 8, 4, 7]
output = filterfalse(lambda L, c=count(): L < 5 and next(c) < 3, data)

그러면 다음 list(output)이 제공됩니다.

[10, 9, 8, 4, 7]

반복 가능, 조건 및 삭제할 양을 취하는 생성기를 작성하십시오. 데이터를 반복하고 조건을 충족하지 않는 항목을 산출합니다. 조건이 충족되면 카운터를 증가시키고 값을 산출하지 마십시오. 카운터가 드롭하려는 양에 도달하면 항상 아이템을 양보하십시오.

def iter_drop_n(data, condition, drop):
    dropped = 0

    for item in data:
        if dropped >= drop:
            yield item
            continue

        if condition(item):
            dropped += 1
            continue

        yield item

data = [1, 10, 2, 9, 3, 8, 4, 7]
out = list(iter_drop_n(data, lambda x: x < 5, 3))

이것은 목록의 추가 사본이 필요하지 않으며 목록을 한 번만 반복하고 각 항목에 대해 한 번만 조건을 호출합니다. 실제로 전체 목록을보고 싶지 않으면 list결과 에서 호출을 중단 하고 반환 된 생성기를 직접 반복합니다.


받아 들여진 대답은 내 취향에 비해 너무 마술 적이었습니다. 다음은 흐름이 좀 더 명확 해지기를 바랍니다.

def matchCondition(x):
    return x < 5


def my_gen(L, drop_condition, max_drops=3):
    count = 0
    iterator = iter(L)
    for element in iterator:
        if drop_condition(element):
            count += 1
            if count >= max_drops:
                break
        else:
            yield element
    yield from iterator


example = [1, 10, 2, 9, 3, 8, 4, 7]

print(list(my_gen(example, drop_condition=matchCondition)))

davidism 답변의 논리와 비슷 하지만 모든 단계에서 드롭 수를 초과 하는지 확인하는 대신 나머지 루프를 단락시킵니다.

참고 :yield from 사용할 수 없는 경우 에서 나머지 항목에 대해 다른 for 루프로 바꾸십시오 iterator.


돌연변이가 필요한 경우 :

def do_remove(ls, N, predicate):
    i, delete_count, l = 0, 0, len(ls)
    while i < l and delete_count < N:
        if predicate(ls[i]):
           ls.pop(i) # remove item at i
           delete_count, l = delete_count + 1, l - 1 
        else:
           i += 1
    return ls # for convenience

assert(do_remove(l, N, matchCondition) == [10, 9, 8, 4, 7])

간단한 Python :

N = 3
data = [1, 10, 2, 9, 3, 8, 4, 7]

def matchCondition(x):
    return x < 5

c = 1
l = []
for x in data:
    if c > N or not matchCondition(x):
        l.append(x)
    else:
        c += 1

print(l)

원하는 경우 쉽게 발전기로 전환 할 수 있습니다.

def filter_first(n, func, iterable):
    c = 1
    for x in iterable:
        if c > n or not func(x):
            yield x
        else:
            c += 1

print(list(filter_first(N, matchCondition, data)))

목록 이해력 사용 :

n = 3
data = [1, 10, 2, 9, 3, 8, 4, 7]
count = 0
def counter(x):
    global count
    count += 1
    return x

def condition(x):
    return x < 5

filtered = [counter(x) for x in data if count < n and condition(x)]

이는 또한 부울 단락으로 인해 n 개의 요소가 발견 된 후에도 조건 확인을 중지합니다 .


시작 Python 3.8할당 표현식 (PEP 572) ( :=연산자) 의 도입으로 목록 이해 내에서 변수를 사용하고 증가시킬 수 있습니다.

# items = [1, 10, 2, 9, 3, 8, 4, 7]
total = 0
[x for x in items if not (x < 5 and (total := total + 1) <= 3)]
# [10, 9, 8, 4, 7]

이:

  • Initializes a variable total to 0 which will symbolize the number of previously matched occurrences within the list comprehension
  • Checks for each item if it both:
    • matches the exclusion condition (x < 5)
    • and if we've not already discarded more than the number of items we wanted to filter out by:
      • incrementing total (total := total + 1) via an assignment expression
      • and at the same time comparing the new value of total to the max number of items to discard (3)

참고URL : https://stackoverflow.com/questions/39580063/remove-the-first-n-items-that-match-a-condition-in-a-python-list

반응형