Split a python list if it contains two consecutive zero's

Viewed 443

I have a python list that represents cities, by integers. City 0 is HQ. For example, a possible route list would be:

[0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0, 
0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0, 
0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0] 

This list contains three routes. How do I split these lists when they have consecutive zero's? So basically my expected output is a nested list where all the elements are seperate routes, like so:

[[0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0], 
[0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0],
[0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0]]

I've tried a number of list comprehensions but I cannot seem to find the right solution...

9 Answers
routes = []
current_route = []
in_route = False

for city in entire_trip:  # entire_trip is your initial list
    if not in_route:
        if city != 0:
            in_route = True
            current_route.append(0)
            current_route.append(city)
    else:
        if city == 0:
            current_route.append(0)
            routes.append(current_route)
            current_route = []
            in_route = False
        else:
            current_route.append(city)
print(routes)

It is not the best solution but...

numbers = [0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0,
0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0, 
0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0]

n = []
pointer = 0
for i in range(len(numbers) -1):
    if numbers[i] ==0 and numbers[i+1] == 0:
        x = numbers[pointer:i+1]
        pointer = i+1
        n.append(x)
x = numbers[pointer:]
n.append(x)
print(n)

Because you care about an element's relation to its neighbor, I wouldn't recommend using a list comprehension.

nums=[0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0, 
0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0, 
0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0]

split_on = []

for i in range(len(nums)-1):
    if nums[i] == 0 and nums[i+1] == 0:
        split_on.append(i+1)

now that we have the "split points" we want to grab the different sub-lists at those indices.


current_ind = 0
visits = []

for index in split_on:
    visits.append(nums[current_ind:index])
    current_ind = index

and now we have all but the last leg of the trip:

visits.append(nums[current_ind:len(nums)+1])
x = [0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0, 
0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0, 
0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0]

item = []
final = []
for i in x :
  if i != 0:
    item.append(i)
  else :
    item.append(i)
    if len(item) > 1 :      
      final.append(item)
      item = []

print(final)

Output:

[[0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0], [0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0], [0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0]]

numpy approach:

import numpy as np

x=[0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0, 
0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0, 
0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0]

res=np.array(x)
res=np.split(res, np.arange(1, len(res))[np.logical_and(res[:-1]==0, res[1:]==0)])

Outputs:

>>> res
[array([  0,   7,  40,  41,  34,  96,  75, 127,  48,  65,  79,  27, 126,
        78,   0]), array([  0,  56,  45,   2,  67,  66, 124,  59,  82, 133, 102,  57,  54,
         0]), array([  0,  64,  97,  81,  87,  80,  61,  98,  52, 101,  83,  60, 109,
        39,  53,   0])]
def break_after_two_zero(array):
    curr_list = []
    for index, value in enumerate(array[:-1]):
        curr_list.append(value)
        if value == array[index + 1] == 0:
            yield curr_list
            curr_list = list()
    if curr_list:
        yield curr_list

data = [0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0, 
        0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0, 
        0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0]
print(list(break_after_two_zero(data)))
# >>> [[0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0],
#      [0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0],
#      [0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0]]

data = [0, 0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0, 0]
print(list(break_after_two_zero(data)))
# >>> [[0], [0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0], [0]]

data = [0, 7, 40, 41, 34, 96, 75, 0, 0, 0, 127, 48, 65, 79, 27, 126, 78, 0]
print(list(break_after_two_zero(data)))
# >>> [[0, 7, 40, 41, 34, 96, 75, 0],
#      [0],
#      [0, 127, 48, 65, 79, 27, 126, 78]]

Just goes to show, 10 ways to do anything ...

Here is a super simple approach with minimal loops, if's and variables:

from itertools import zip_longest

# Setup testing list.
l = [0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0, 
     0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0, 
     0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0] 

# Initialise.
d = {}
k = 0

# Split list based on requirements.
for i, j in zip_longest(l, l[1:]):
    d.setdefault(k, []).append(i)
    if all([i == 0, j == 0]):
        k += 1

# Unpack results.
result = [v for v in d.values()]

Output:

[[0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0],
 [0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0],
 [0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0]]

Other possible solutions:

res = [[]]

for i in range(len(data)):
    res[-1].append(data[i])
    if data[i] == 0 and i < len(data) - 1 and data[i + 1] == 0:
        res.append([])

and

it = iter(data)

res = [[0, *iter(it.__next__, 0), 0] for _ in it]

print(res)

Both give the same output:

[
    [0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0],
    [0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0],
    [0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0],
]

Other possible solutions: turn list to str,then string processing.

    aa = [0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0, 
        0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0, 
        0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0] 
    bb = map(str, aa)
    str_city = "-".join(bb)
    routes = str_city.replace('-0-0','+').split('+')
    current_routes = [map(int, "0-{0}-0".format(route.strip('0').strip('-')).split('-')) for route in routes ]
    print(current_routes)

result:

[[0, 7, 40, 41, 34, 96, 75, 127, 48, 65, 79, 27, 126, 78, 0], 
[0, 56, 45, 2, 67, 66, 124, 59, 82, 133, 102, 57, 54, 0], 
[0, 64, 97, 81, 87, 80, 61, 98, 52, 101, 83, 60, 109, 39, 53, 0]]
Related