sharafjaffri
sharafjaffri

Reputation: 2204

interval in python

I have sorted list of datetime.time and want to create intervals like. If I have

a = [datetime.time(0,0), datetime.time(8,0), datetime.time(13,0), datetime.time(17,0)]

Then result should be like this:

c = [[datetime.time(0,0),datetime.time(8,0)], [datetime.time(8,0),datetime.time(13,0)],
[datetime.time(13,0),datetime.time(17,0)], [datetime.time(17,0),datetime.time(0,0)]]

This could be achieved using simple loop but if there is better solution exist?

Using loop:

>>> a=[datetime.time(0, 0), datetime.time(3, 0), datetime.time(8, 0), datetime.time(11, 0)]
>>> 
>>> r = []
>>> 
>>> for i in range(0,len(a)):
...     if i+1 < len(a):
...         r.append([a[i],a[i+1]])
...     else:
...         r.append([a[i],a[0]])
... 
>>> r
[[datetime.time(0, 0), datetime.time(3, 0)], [datetime.time(3, 0), datetime.time(8, 0)], [datetime.time(8, 0), datetime.time(11, 0)], [datetime.time(11, 0), datetime.time(0, 0)]]
>>> 

nd what could be change if I want result to be

[[datetime.time(0, 0), datetime.time(2, 59, 59)], [datetime.time(3, 0), datetime.time(7, 59, 59)], [datetime.time(8, 0), datetime.time(10, 59, 59)], [datetime.time(11, 0), datetime.time(23, 59, 59)]]

Upvotes: 1

Views: 27135

Answers (5)

Mero
Mero

Reputation: 1

You can use the more_itertools library which is a recipe code around the python standard library itertools. If you want to process elements while iterating:

import more_itertools as more
rv = [(x, y) for (x, y) in more.pairwise(a)]

or simply:

rv = list(more.pairwise(a))

Also as stated before is an answer, zip is also a good choice:

rv = list(zip(a[:-1], a[1:]))

Upvotes: 0

aneroid
aneroid

Reputation: 15962

One more option1 as a one-liner: but with a really unpythonic expression (imho) so that you don't have to append the last and first pair in a separate step:

>>> [list(i) for i in zip(a, a[1:]+[a[0]])]
[[datetime.time(0, 0), datetime.time(8, 0)],
 [datetime.time(8, 0), datetime.time(13, 0)],
 [datetime.time(13, 0), datetime.time(17, 0)],
 [datetime.time(17, 0), datetime.time(0, 0)]]

1 zip method inspired by Pierre-GM's solution above.

FYI, I prefer either my initial answer or Pierre's over this.


Edit/Update for 2nd part of the question: To do the timedeltas in one expression also (but I see no good reason why this shouldn't just be split out into different statements instead...):

>>> [[i, (datetime.datetime(101, 1, 1, j.hour, j.minute, j.second) -
...       datetime.timedelta(seconds=1)
...      ).time()
...  ] for i,j in zip(a, a[1:]+[a[0]])
... ]
[[datetime.time(0, 0), datetime.time(7, 59, 59)],
 [datetime.time(8, 0), datetime.time(12, 59, 59)],
 [datetime.time(13, 0), datetime.time(16, 59, 59)],
 [datetime.time(17, 0), datetime.time(23, 59, 59)]]

Upvotes: 3

Pierre GM
Pierre GM

Reputation: 20329

You could try

a = list(zip(a[:-1], a[1:]))
a.append((a[-1], a[0])])

That gives you a list of tuples. If you want a list of lists, just do

>>> a = [list(i) for i in zip(a[:-1], a[1:])]
>>> a.append([a[-1], a[0]])

(Edited version taking 1. the [a[-1],a[0]] out of the list comprehension and 2. the fact that zip doesn't return a list in Python 3+)

Yet another possibility would be to just append the first value to the list:

>>> tmp = a + a[0]
>>> list(zip(tmp[:,-1], tmp[1:]))

It can be argued that it creates a temporary list. You could do aa.append(a[0]) instead but then you'd modify your initial list, which might be an issue.

Upvotes: 9

mgilson
mgilson

Reputation: 309821

For creating a range like this, I might try a generator:

def make_ranges(lst):
    max_idx = len(lst) - 1
    for i,item in enumerate(lst):
        yield [item, lst[i+1 if i != max_idx else 0] ]

You could play around with keyword arguments to tell make_ranges whether or not to be periodic and if periodic, whether or not to include the wraparound at the beginning or the end.

Then you can make your ranges:

a = [1,2,3,4,5,6,7,8]
b = list(make_ranges(a))
print(b == [[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,8],[8,1]]) #True

Upvotes: 5

aneroid
aneroid

Reputation: 15962

How about a list comprehension if not a 'simple loop'? Like:

>>> b = [[a[x], a[x+1]] for x in range(0, len(a)-1)] + [[a[-1], a[0]]]
>>> b
[[datetime.time(0, 0), datetime.time(8, 0)],
 [datetime.time(8, 0), datetime.time(13, 0)],
 [datetime.time(13, 0), datetime.time(17, 0)],
 [datetime.time(17, 0), datetime.time(0, 0)]]

Upvotes: 2

Related Questions