Python 'for' 루프에서 마지막 요소를 감지하는 Python 방식은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1630320

문제

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

이것은 반복 가능한 모든 사람들에게도 효과가있을 것입니다. 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() a를 사용하는 것보다 for "특별한 경우"루프.


동일한 원칙을 사용하지만 더 컴팩트 한 것 :

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

친숙해 보이지 않습니까? :)


@ofko 및 실제로 반복 할 수 없는지 확인 해야하는 다른 사람들의 경우 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

다른 팁

'코드 사이'는 그 예이다. 머리-꼬리 무늬.

항목이 있고 그 뒤에 일련의 ( between, item ) 쌍이 옵니다.또한 이를 항목이 뒤따르는 일련의 (항목, 사이) 쌍으로 볼 수도 있습니다.일반적으로 첫 번째 요소를 특수 요소로 사용하고 나머지 요소를 "표준" 사례로 사용하는 것이 더 간단합니다.

또한 코드 반복을 방지하려면 반복하고 싶지 않은 코드를 포함하는 함수나 기타 개체를 제공해야 합니다.삽입 만약에 한 번을 제외하고 항상 거짓인 루프의 문은 어리석은 일입니다.

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 )

이는 증명하기가 약간 더 쉽기 때문에 더 신뢰할 수 있고, 추가 데이터 구조(예: 목록의 복사본)를 생성하지 않으며 낭비되는 많은 실행을 필요로 하지 않습니다. 만약에 한 번만 제외하고 항상 거짓인 조건입니다.

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

L[-1]

그러나 그것은 당신이 그보다 더 많은 일을하고있는 것 같습니다. 당신의 길에는 아무런 문제가 없습니다. 나는 심지어 일부를 한 눈에 보았습니다 장고 코드 템플릿 태그를 위해 기본적으로 당신이하는 일을합니다.

그 질문은 꽤 오래되었지만 Google을 통해 여기에 와서 아주 간단한 방법을 찾았습니다. 목록 슬라이스. 모든 목록 항목 사이에 '&'를 넣고 싶다고 가정 해 봅시다.

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

이것은 '1 & 2 & 3'을 반환합니다.

이것은 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

항목이 고유 한 경우 :

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

입력 데이터의 슬라이딩 창을 사용하여 다음 값을 엿볼 수 있고 센티넬을 사용하여 마지막 값을 감지 할 수 있습니다. 이것은 반복 가능한 모든 것에서 작동하므로 길이를 미리 알 필요가 없습니다. 쌍별 구현은 왔습니다 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

마지막 요소를 반복하고 마지막 요소를 반복 할 가능성이 없으며 루프 외부의 마지막 요소를 취급합니까? 결국, 루프는 당신이 루프를 뒤집는 모든 요소와 유사한 일을하도록 만들어집니다. 하나의 요소에 특별한 것이 필요한 경우 루프에 있어서는 안됩니다.

(이 질문 참조 : 루프-a 루프 러브-분리 된 치료)

편집 : 질문은 "사이의"에 관한 것이므로 첫 번째 요소는 이전 모델이 없거나 마지막 요소는 후임자가 없다는 점에서 특별합니다.

10 만 루프가없고 "명령문 인 경우 100,000"을 절약하기를 원하지 않는 한, 당신의 길에는 아무런 문제가 없습니다. 이 경우 그런 식으로 갈 수 있습니다.

iterable = [1,2,3] # Your date
iterator = iter(iterable) # get the data iterator

try :   # wrap all in a try / except
    while 1 : 
        item = iterator.next() 
        print item # put the "for loop" code here
except StopIteration, e : # make the process on the last element here
    print item

출력 :

1
2
3
3

그러나 실제로, 당신의 경우 나는 그것이 과잉 인 것 같습니다.

어쨌든, 당신은 아마도 슬라이스에 더 운이 좋을 것입니다.

for item in iterable[:-1] :
    print item
print "last :", iterable[-1]

#outputs
1
2
last : 3

또는 그냥 :

for item in iterable :
    print item
print iterable[-1]

#outputs
1
2
3
last : 3

결국, 당신을 할 수있는 키스 방법은 __len__ :

item = ''
for item in iterable :
    print item
print item

OUPUTS :

1
2
3
3

내가 그렇게 할 것 같은 느낌이라면, 나에게 간단 해 보인다.

슬라이스와 is 마지막 요소를 확인하려면 :

for data in data_list:
    <code_that_is_done_for_every_element>
    if not data is data_list[-1]:
        <code_that_is_done_between_elements>

경고 emptor: 이것은 목록의 모든 요소가 실제로 다른 경우에만 작동합니다 (메모리에 위치가 다릅니다). 후드 아래에서 파이썬은 동일한 요소를 감지하고 동일한 물체를 재사용 할 수 있습니다. 예를 들어, 동일한 값과 공통 정수의 문자열의 경우.

Google 은이 오래된 질문에 저를 가져 왔으며이 문제에 대해 다른 접근 방식을 추가 할 수 있다고 생각합니다.

여기의 대부분의 답변은 요청 된대로 루프 제어를위한 적절한 처리를 처리하지만 Data_List가 파괴 가능하면 빈 목록이 끝날 때까지 목록에서 항목을 팝업하는 것이 좋습니다.

while True:
    element = element_list.pop(0)
    do_this_for_all_elements()
    if not element:
        do_this_only_for_last_element()
        break
    do_this_for_all_elements_but_last()

당신은 심지어 사용할 수도 있습니다 LEN (Element_List) 마지막 요소로 아무것도 할 필요가 없다면. 이 솔루션이 더 우아한 다음 Next ()를 다루는 것을 발견합니다.

나는 @ethan-t의 접근을 좋아하지만 while True 내 관점에서 위험합니다.

while L:
    e = L.pop(0)
    # process element
    if not L:
        print('Last element has been detected.')

루프가 끝날 때까지 마지막 항목의 특수 처리를 지연시킵니다.

>>> for i in (1, 2, 3):
...     pass
...
>>> i
3

반복자로 입력을 가정하면 여기에 Itertools의 Tee 및 Izip을 사용하는 방법이 있습니다.

from itertools import tee, izip
items, between = tee(input_iterator, 2)  # Input must be an iterator.
first = items.next()
do_to_every_item(first)  # All "do to every" operations done to first item go here.
for i, b in izip(items, between):
    do_between_items(b)  # All "between" operations go here.
    do_to_every_item(i)  # All "do to every" operations go here.

데모:

>>> def do_every(x): print "E", x
...
>>> def do_between(x): print "B", x
...
>>> test_input = iter(range(5))
>>>
>>> from itertools import tee, izip
>>>
>>> items, between = tee(test_input, 2)
>>> first = items.next()
>>> do_every(first)
E 0
>>> for i,b in izip(items, between):
...     do_between(b)
...     do_every(i)
...
B 0
E 1
B 1
E 2
B 2
E 3
B 3
E 4
>>>

당신이 목록을 겪고 있다면, 나에게도 이것도 효과가있었습니다.

for j in range(0, len(Array)):
    if len(Array) - j > 1:
        notLast()

내 마음에 오는 가장 간단한 해결책은 다음과 같습니다.

for item in data_list:
    try:
        print(new)
    except NameError: pass
    new = item
print('The last item: ' + str(new))

따라서 우리는 항상 하나의 반복을 지연시켜 하나의 항목을 미리 봅니다. 첫 번째 반복 중에 무언가를 건너 뛰기 위해 나는 단순히 오류를 포착합니다.

물론 당신은 NameError 원할 때 자란.

또한`counstruct를 유지하십시오

try:
    new
except NameError: pass
else:
    # continue here if no error was raised

이것은 새로운 이름이 이전에 정의되지 않았다는 것입니다. 편집증이라면이를 확인할 수 있습니다 new 사용하지 않습니다 :

try:
    del new
except NameError:
    pass

또는 물론 IF 문 (IF 문)도 사용할 수 있습니다 (if notfirst: print(new) else: notfirst = True). 그러나 내가 아는 한 오버 헤드가 더 큽니다.


Using `timeit` yields:

    ...: try: new = 'test' 
    ...: except NameError: pass
    ...: 
100000000 loops, best of 3: 16.2 ns per loop

그래서 나는 오버 헤드가 무시할 수 없을 것으로 기대합니다.

품목을 한 번 세고 남은 품목 수를 따라 잡으십시오.

remaining = len(data_list)
for data in data_list:
    code_that_is_done_for_every_element

    remaining -= 1
    if remaining:
        code_that_is_done_between_elements

이렇게하면 목록의 길이 만 한 번만 평가합니다. 이 페이지의 많은 솔루션은 길이를 미리 사용할 수 없다고 가정하지만 이는 질문의 일부가 아닙니다. 길이가있는 경우 사용하십시오.

나에게 목록 끝에서 특별한 사례를 처리하는 가장 간단하고 피해자 방법은 다음과 같습니다.

for data in data_list[:-1]:
    handle_element(data)
handle_special_element(data_list[-1])

물론 이것은 첫 번째 요소를 특별한 방식으로 처리하는 데 사용될 수 있습니다.

여러 가지 방법이있을 수 있습니다. 슬라이스가 가장 빠릅니다. .index () 메소드를 사용하는 하나 더 추가 :

>>> l1 = [1,5,2,3,5,1,7,43]                                                 
>>> [i for i in l1 if l1.index(i)+1==len(l1)]                               
[43]
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top