1

So I was wondering if there is a way to print the nth value (not the last value) from a For Loop output. For eg: let's suppose I want to print just the 'fifth-to-last' value or just the 'third-to-last' value from the For Loop output. Any idea how can I do that? I am newbie at coding/python and I am building up this code after doing a lot of research & learning on the way. So any help appreciated.

Currently, the code below is giving me the last value.

from datetime import timedelta, date

def daterange(start_date, end_date):
    for n in range(int(start_date.day), int((end_date - start_date).days), 90):
        yield start_date + timedelta(n)

start_date = date(2016, 1, 1)
end_date = date.today()
for single_date in daterange(start_date, end_date):
    x = single_date.strftime("%Y-%m-%d")

print(x)
  • A problem with this code is it assumes (implicitly) that the iterator is non-empty. If the iterator happens to be empty it'll raise `UnboundLocalError`. – Masklinn Mar 09 '20 at 06:56
  • Well, I got the code from this link here. https://stackoverflow.com/questions/1060279/iterating-through-a-range-of-dates-in-python I wasn't aware of this issue. How can I fix this? – Sourav Chatterjee Mar 09 '20 at 07:17

3 Answers3

3

The technique is to accumulate the results in a container, and then print the n-th element back.

One possibility is to use collections.deque() with a maxlen value set to n.

from datetime import timedelta, date
from collections import deque

def daterange(start_date, end_date):
    for n in range(int(start_date.day), int((end_date - start_date).days), 90):
        yield start_date + timedelta(n)

window = deque([], maxlen=5)
start_date = date(2016, 1, 1)
end_date = date.today()
for single_date in daterange(start_date, end_date):
    x = single_date.strftime("%Y-%m-%d")
    window.append(x)

print(window[0])

The above code outputs the fifth oldest entry.

2018-12-17

The above code accumulates the most recent values in a sliding window of width 5. The oldest value in at position 0 and the newest value is at position -1.

You can change the 5 to be any value of n that you need.

Hope this helps :-)

Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
  • 1
    Yes, this helps a lot. :) I would never have been able to guess this. Also, I learned about something new as well. Thank you so much. – Sourav Chatterjee Mar 09 '20 at 07:00
  • 1
    This might be quite memory-consiming if you're looking for nth element for large `n`. I think Raghul Raj's solution is better for general case. – Błotosmętek Mar 09 '20 at 07:22
  • The OP listed examples of 3rd to last or 5th to last. There was no mention of hundreds of thousands or millions that would consume much memory. – Raymond Hettinger Mar 09 '20 at 07:27
1

You can use enumerate while looping which gives the iteration count. You can provide a condition inside based on the values you need to print as follows:

from datetime import timedelta, date

def daterange(start_date, end_date):
    for n in range(int(start_date.day), int((end_date - start_date).days), 90):
        yield start_date + timedelta(n)

start_date = date(2016, 1, 1)
end_date = date.today()
n=5
length =len(list(daterange(start_date, end_date)))

for i,single_date in enumerate(daterange(start_date, end_date)):
    x = single_date.strftime("%Y-%m-%d")
    if i == length-n:
        print(x)

Hope that helps

Raghul Raj
  • 1,428
  • 9
  • 24
0

You can use slicing to only get certain elements by index. Slicing does not work on generators however, so you will need to cast to a list.

from datetime import timedelta, date

def daterange(start_date, end_date):
    for n in range(int(start_date.day), int((end_date - start_date).days), 90):
       yield start_date + timedelta(n)

start_date = date(2016, 1, 1)
end_date = date.today()
for single_date in list(daterange(start_date, end_date))[4:]:
    x = single_date.strftime("%Y-%m-%d")
    print(x)

This will print the 5th (index: 4) to last element.

Erathiian
  • 140
  • 1
  • 6