'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
'코드 사이'는 헤드-테일 패턴 의 예입니다 .
아이템이 있고 그 뒤에 (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]
그러나 그 이상을하고있는 것처럼 보입니다. 당신의 길에는 아무런 문제가 없습니다. 템플릿 태그에 대한 일부 장고 코드 를 간략히 살펴 보았으며 기본적으로 수행중인 작업을 수행합니다.
그 질문은 꽤 오래되었지만 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
입력 데이터 위에 슬라이딩 창을 사용하여 다음 값을 살짝보고 센티넬을 사용하여 마지막 값을 감지 할 수 있습니다. 이것은 모든 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
마지막 요소를 모두 반복하고 마지막 요소를 루프 외부에서 처리 할 수 있습니까? 결국, 루프는 루프하는 모든 요소와 유사한 것을 수행하기 위해 만들어집니다. 하나의 요소에 특별한 무언가가 필요한 경우 루프에 있으면 안됩니다.
(이 질문도 참조하십시오 : 마지막 요소에 루프 루프가 필요합니다. 별도의 처리 )
편집 : 질문은 "사이에"에 관한 것이기 때문에 첫 번째 요소는 전임자가 없다는 점에서 특별한 요소 이거나 마지막 요소는 후임자가 없다는 점에서 특별합니다.
100 000 개의 루프가 있고 100 000 "if"문을 저장하지 않는 한, 당신의 방법에는 아무런 문제가 없습니다. 이 경우 다음과 같이 갈 수 있습니다.
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
결국 KISS 방식으로 작업을 수행하면 다음이없는 것을 포함하여 모든 iterable과 작동합니다 __len__
.
item = ''
for item in iterable :
print item
print item
출력 :
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>
Caveat emptor: This only works if all elements in the list are actually different (have different locations in memory). Under the hood, Python may detect equal elements and reuse the same objects for them. For instance, for strings of the same value and common integers.
Google brought me to this old question and I think I could add a different approach to this problem.
Most of the answers here would deal with a proper treatment of a for loop control as it was asked, but if the data_list is destructible, I would suggest that you pop the items from the list until you end up with an empty 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()
you could even use while len(element_list) if you don't need to do anything with the last element. I find this solution more elegant then dealing with next().
I like the approach of @ethan-t, but while True
is dangerous from my point of view.
while L:
e = L.pop(0)
# process element
if not L:
print('Last element has been detected.')
Delay the special handling of the last item until after the loop.
>>> for i in (1, 2, 3):
... pass
...
>>> i
3
Instead of counting up, you can also count down:
nrToProcess = len(list)
for s in list:
s.doStuff()
nrToProcess -= 1
if nrToProcess==0: # this is the last one
s.doSpecialStuff()
Assuming input as an iterator, here's a way using tee and izip from itertools:
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.
Demo:
>>> 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
>>>
if you are going through the list, for me this worked too:
for j in range(0, len(Array)):
if len(Array) - j > 1:
notLast()
The most simple solution coming to my mind is:
for item in data_list:
try:
print(new)
except NameError: pass
new = item
print('The last item: ' + str(new))
So we always look ahead one item by delaying the the processing one iteration. To skip doing something during the first iteration I simply catch the error.
Of course you need to think a bit, in order for the NameError
to be raised when you want it.
Also keep the `counstruct
try:
new
except NameError: pass
else:
# continue here if no error was raised
This relies that the name new wasn't previously defined. If you are paranoid you can ensure that new
doesn't exist using:
try:
del new
except NameError:
pass
Alternatively you can of course also use an if statement (if notfirst: print(new) else: notfirst = True
). But as far as I know the overhead is bigger.
Using `timeit` yields:
...: try: new = 'test'
...: except NameError: pass
...:
100000000 loops, best of 3: 16.2 ns per loop
so I expect the overhead to be unelectable.
Count the items once and keep up with the number of items remaining:
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
This way you only evaluate the length of the list once. Many of the solutions on this page seem to assume the length is unavailable in advance, but that is not part of your question. If you have the length, use it.
For me the most simple and pythonic way to handle a special case at the end of a list is:
for data in data_list[:-1]:
handle_element(data)
handle_special_element(data_list[-1])
Of course this can also be used to treat the first element in a special way .
There can be multiple ways. slicing will be fastest. Adding one more which uses .index() method:
>>> l1 = [1,5,2,3,5,1,7,43]
>>> [i for i in l1 if l1.index(i)+1==len(l1)]
[43]
'Programming' 카테고리의 다른 글
디버거는 어떻게 작동합니까? (0) | 2020.06.03 |
---|---|
반응 구성 요소 외부에서 Redux Store에 액세스하는 가장 좋은 방법은 무엇입니까? (0) | 2020.06.03 |
HAXM으로 OS X v10.9 (Mavericks)를 고정하는 Android 에뮬레이터 (0) | 2020.06.03 |
C # .NET에서 App.config는 무엇입니까? (0) | 2020.06.03 |
Agda와 Idris의 차이점 (0) | 2020.06.03 |