get the sum of differences between integers in a list
Peter Otten
__peter__ at web.de
Wed Sep 21 10:42:41 EDT 2016
Daiyue Weng wrote:
> Hi, first of all, let me rephase the problem.
>
> For an arbitrary list of integers (the integers in the list are not
> necessary to be sequential), e.g. [1,2,3,6,8,9,10,11,13],
>
> if a set of consecutive integers having a difference of 1 between them,
> put them in a list, i.e. there are two such lists in this example,
>
> [1,2,3],
>
> [8,9,10,11],
>
> and then put such lists in another list (i.e. [[1,2,3], [8,9,10,11]]). Put
> the rest integers (non-sequential) in a separated list, i.e.
>
> `[6, 13]`.
>
> Note that, the problem only considers sequential integers with step_size =
> 1.
>
> I tried to use itertools.groupby and itertools.count,
>
> from itertools import groupby, count
> lst = [1,2,3,6,8,9,10,11,13]
> c = count()
> result = [list(g) for i, g in groupby(lst, key=lambda x: x-next(c))]
>
> but the result is close to the requirement shown as a list of lists,
>
> [[1, 2, 3], [6], [8, 9, 10, 11], [13]]
>
> but it didn't separate sequential lists from non-sequential ones.
> Also, I couldn't find a way to put [6] and [13] in a single list.
>
> I have also tried to separate sequential lists from non-sequential ones,
>
> result = [list(g) for i, g in groupby(lst, key=lambda x: x-next(c) == 1)]
> # tried to extract [1,2,3] and [8,9,10,11] from the list
>
> or
>
> result = [list(g) for i, g in groupby(lst, key=lambda x: x-next(c) > 1)] #
> tried to extract [6] and [13] from the list
>
> but they all ended up with
>
> [[1, 2, 3], [6, 8, 9, 10, 11, 13]]
>
> So two questions here,
>
> 1. How does itertools.groupby key function work in my case?
>
> 2. How to improve the program to achieve my goals?
OK, you did at least try this time. So here's my attempt:
$ cat consecutive.py
from itertools import chain, groupby, islice, tee
def lonely(triple):
left, value, right = triple
if left is not None and value - left == 1:
return False
if right is not None and right - value == 1:
return False
return True
def grouped(values):
left, mid, right = tee(values, 3)
triples = zip(
chain([None], left),
mid,
chain(islice(right, 1, None), [None])
)
for key, group in groupby(triples, lonely):
yield key, (value for left, value, right in group)
def main():
consecutive = []
other = []
values = [1, 2, 3, 6, 8, 9, 10, 11, 13, 17, 19]
for is_lonely, group in grouped(values):
if is_lonely:
other.extend(group)
else:
consecutive.append(list(group))
print("input")
print(" ", values)
print()
print("consecutive")
print(" all ", consecutive)
print(" shortest", min(consecutive, key=len))
print(" longest ", max(consecutive, key=len))
print()
print("other")
print(" ", other)
if __name__ == "__main__":
main()
$ python3 consecutive.py
input
[1, 2, 3, 6, 8, 9, 10, 11, 13, 17, 19]
consecutive
all [[1, 2, 3], [8, 9, 10, 11]]
shortest [1, 2, 3]
longest [8, 9, 10, 11]
other
[6, 13, 17, 19]
$
This is not as efficient as it should be -- the gaps are calculated twice,
the check for the first and the last position is repeated on every iteration
lots of packing and unpacking... -- either groupby() is the wrong tool or
I'm holding it wrong ;)
More information about the Python-list
mailing list