[python] ‘for’루프에서 마지막 요소를 감지하는 pythonic 방법은 무엇입니까?

for 루프에서 마지막 요소에 대해 특별한 처리를 수행하는 가장 좋은 방법 (보다 콤팩트하고 “파이 토닉 한”방법)을 알고 싶습니다. 사이에 호출해야하는 코드가 있습니다요소 마지막 에서는 표시되지 않습니다.

내가 현재하는 방법은 다음과 같습니다.

for i, data in enumerate(data_list):
    code_that_is_done_for_every_element
    if i != len(data_list) - 1:
        code_that_is_done_between_elements

더 좋은 방법이 있습니까?

참고 :을 사용하는 것과 같은 핵으로 만들고 싶지 않습니다 reduce.;)



답변

대부분의 경우 첫 번째 반복을 마지막 반복 대신 특별한 경우 로 만드는 것이 더 쉽고 저렴 합니다.

first = True
for data in data_list:
    if first:
        first = False
    else:
        between_items()

    item()

이것은 iterable이없는 경우에도 가능합니다 len().

file = open('/path/to/file')
for line in file:
    process_line(line)

    # No way of telling if this is the last line!

그 외에도, 당신이하려는 일에 달려 있기 때문에 일반적으로 우수한 해결책이 없다고 생각합니다. 예를 들어, 목록에서 문자열을 작성하는 경우 “특별한 경우”루프 를 사용하는 str.join()것보다 자연스럽게 사용하는 것이 좋습니다 for.


동일한 원리를 사용하지만 더 간결합니다.

for i, line in enumerate(data_list):
    if i > 0:
        between_items()
    item()

익숙하지 않습니까? 🙂


@ofko와 iterable이없는 iterable의 현재 값이 len()마지막 값인지 실제로 알아야하는 다른 사람들을 위해 , 당신은 미리 봐야합니다 :

def lookahead(iterable):
    """Pass through all values from the given iterable, augmented by the
    information if there are more values to come after the current one
    (True), or if it is the last value (False).
    """
    # Get an iterator and pull the first value.
    it = iter(iterable)
    last = next(it)
    # Run the iterator to exhaustion (starting from the second value).
    for val in it:
        # Report the *previous* value (more to come).
        yield last, True
        last = val
    # Report the last value.
    yield last, False

그런 다음 다음과 같이 사용할 수 있습니다.

>>> for i, has_more in lookahead(range(3)):
...     print(i, has_more)
0 True
1 True
2 False


답변

그 질문은 꽤 오래되었지만 Google을 통해 여기에 왔으며 매우 간단한 방법 인 목록 슬라이싱을 발견했습니다. 모든 목록 항목 사이에 ‘&’를 넣고 싶다고 가정 해 봅시다.

s = ""
l = [1, 2, 3]
for i in l[:-1]:
    s = s + str(i) + ' & '
s = s + str(l[-1])

‘1 & 2 & 3’을 반환합니다.


답변

‘코드 사이’는 헤드-테일 패턴 의 예입니다 .

아이템이 있고 그 뒤에 (item) 쌍의 시퀀스가옵니다. 이 항목을 순서대로 (항목, 사이) 쌍으로 볼 수도 있습니다. 일반적으로 첫 번째 요소를 특별하고 다른 모든 요소를 ​​”표준”사례로 사용하는 것이 더 간단합니다.

또한 코드 반복을 피하려면 반복하지 않으려는 코드를 포함하는 함수 또는 다른 객체를 제공해야합니다. 루프에 if 문을 포함시키는 것은 한 번만 제외하고 항상 거짓입니다.

def item_processing( item ):
    # *the common processing*

head_tail_iter = iter( someSequence )
head = head_tail_iter.next()
item_processing( head )
for item in head_tail_iter:
    # *the between processing*
    item_processing( item )

이것은 증명하기가 조금 더 쉬우므로 더욱 신뢰할 수 있으며, 추가 데이터 구조 (예 : 목록의 사본)를 만들지 않으며 if 조건을 한 번만 제외하고 항상 거짓 인 if 조건을 많이 낭비하지 않아도 됩니다.


답변

마지막 요소를 수정하려는 경우 data_list간단히 표기법을 사용할 수 있습니다.

L[-1]

그러나 그 이상을하고있는 것처럼 보입니다. 당신의 길에는 아무런 문제가 없습니다. 템플릿 태그에 대한 일부 장고 코드간략히 살펴 보았으며 기본적으로 수행중인 작업을 수행합니다.


답변

품목이 고유 한 경우 :

for x in list:
    #code
    if x == list[-1]:
        #code

다른 옵션:

pos = -1
for x in list:
    pos += 1
    #code
    if pos == len(list) - 1:
        #code


for x in list:
    #code
#code - e.g. print x


if len(list) > 0:
    for x in list[:-1]
        #code
    for x in list[-1]:
        #code


답변

이것은 Ants Aasma의 접근 방식과 유사하지만 itertools 모듈을 사용하지 않습니다. 또한 반복자 스트림에서 단일 요소를 미리 보는 지연 반복자입니다.

def last_iter(it):
    # Ensure it's an iterator and get the first field
    it = iter(it)
    prev = next(it)
    for item in it:
        # Lag by one item so I know I'm not at the end
        yield 0, prev
        prev = item
    # Last item
    yield 1, prev

def test(data):
    result = list(last_iter(data))
    if not result:
        return
    if len(result) > 1:
        assert set(x[0] for x in result[:-1]) == set([0]), result
    assert result[-1][0] == 1

test([])
test([1])
test([1, 2])
test(range(5))
test(xrange(4))

for is_last, item in last_iter("Hi!"):
    print is_last, item


답변

입력 데이터 위에 슬라이딩 창을 사용하여 다음 값을 살짝보고 센티넬을 사용하여 마지막 값을 감지 할 수 있습니다. 이것은 모든 iterable에서 작동하므로 미리 길이를 알 필요가 없습니다. pairwise 구현은 itertools 레시피 에서 가져온 것 입니다.

from itertools import tee, izip, chain

def pairwise(seq):
    a,b = tee(seq)
    next(b, None)
    return izip(a,b)

def annotated_last(seq):
    """Returns an iterable of pairs of input item and a boolean that show if
    the current item is the last item in the sequence."""
    MISSING = object()
    for current_item, next_item in pairwise(chain(seq, [MISSING])):
        yield current_item, next_item is MISSING:

for item, is_last_item in annotated_last(data_list):
    if is_last_item:
        # current item is the last item