У меня есть список, который содержит нули и ненулевые значения. Я хочу найти диапазон нулей и ненулевых значений в терминах кортежа внутри списка. Я ищу пакетное решение с питоническим способом. Например.

a = [ 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   5,  11,  12,
        12,  12,  13,  13,  17,  17,  17,  17,  17,  17,  17,  17,  17,
        25,  42,  54,  61,  61,  68,  73, 103, 115, 138, 147, 170, 187,
       192, 197, 201, 208, 210, 214, 216, 217, 217, 218, 219, 220, 221,
       222, 222, 219, 220, 220, 221, 220, 216, 216, 217, 217, 217, 217,
       216, 216, 216, 209, 204, 193, 185, 177, 161, 156, 143, 110, 103,
        89,  82,  62,  62,  62,  60,  56,  55,  50,  49,  48,  47,  47,
        45,  44,  43,  42,  40,  37,  23,  22,  14,  12,   6,   0,   0,
         0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
         0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   5,
         6,   6,   6,   7,   7,   7,  13,  29,  31,  32,  33,  41,  42,
        43,  43,  44,  44,  44,  44,  44,  60,  70,  71,  72,  88,  95,
       104, 105, 111, 124, 125, 131, 145, 157, 169, 174, 186, 190, 190,
       191, 192, 192, 193, 193, 193, 194, 198, 201, 202, 203, 202, 203,
       203, 203, 203, 203, 203, 197, 195, 186, 177, 171, 154, 153, 148,
       141, 140, 135, 132, 120, 108,  94,  86,  78,  73,  60,  53,  46,
        46,  45,  44,  43,  37,  35,  29,  26,  19,  11,   0]]

Результат: idx = [(0,9), (10 101), (102 128), ...]

2
Zara 26 Фев 2018 в 13:52

5 ответов

Лучший ответ

Вот мое предложение без внешних пакетов, короткое, читаемое и легко понятное:

# Compute list "b" by replacing any non-zero value of "a" with 1
b = list(map(int,[i != 0 for i in a]))

#Compute ranges of 0 and ranges of 1
idx = []   # result list of tuples
ind = 0    # index of first element of each range of zeros or non-zeros
for n,i in enumerate(b):
    if (n+1 == len(b)) or (b[n] != b[n+1]):
        # Here: EITHER it is the last value of the list 
        #       OR a new range starts at index n+1
        idx.append((ind,n))
        ind = n+1

print(idx)
3
Laurent H. 26 Фев 2018 в 11:57

Нет необходимости в импорте (поэтому не нужно искать документы библиотеки, чтобы понять, как работает этот импорт :-) и с комментариями.

# results is the output list, each entry is a list of startindex,stopindex
results = []
# each time round the logical value is remembered in previouslvalue
previouslvalue = None
for i,value in enumerate(a):
    # get the logical value (==0/!=0) from value
    lvalue = True if value != 0 else False
    if previouslvalue is None or lvalue != previouslvalue:
        # this is either the first entry, or the lvalue has changed
        # either way, append a new entry to results, with the current index as start/finish of the run
        results.append([i,i])
    else:
        # same lvalue as previous, extend the last entry to include this index
        results[-1][1] = i
    # save the logical value for next time round the loop
    previouslvalue = lvalue
print results

Выход:

[[0, 9], [10, 101], [102, 128], [129, 217], [218, 252], [253, 338], [339, 362], [363, 447], [448, 490], [491, 580], [581,581]]

Отвечая на комментарий о включении логического значения в список результатов, это очень просто:

# results is the output list, each entry is a list of startindex,stopindex
results = []
# each time round the 
previouslvalue = None
for i,value in enumerate(a):
    # get the logical value (==0/!=0) from value
    lvalue = True if value != 0 else False
    if previouslvalue is None or lvalue != previouslvalue:
        # this is either the first entry, or the lvalue has changed
        # either way, append a new entry to results, with the current index as start/finish of the run
        # include the logical value in the list of results
        results.append([i,i,lvalue])
    else:
        # same lvalue as previous, extend the last entry to include this index
        results[-1][1] = i
    # save the logical value for next time round the loop
    previouslvalue = lvalue
print results

Выход сейчас:

[[0, 9, False], [10, 101, True], [102, 128, False], [129, 217, True], [218, 252, False], [253, 338, True], [339, 362, False], [363, 447, True], [448, 490, False], [491, 580, True], [581, 581, False]]
1
barny 26 Фев 2018 в 13:35

Вы могли бы enumerate() получить индексы, itertools.groupby() сгруппировать ложные (0) и истинные значения вместе и извлечь начальный и конечный индексы с помощью operator.itemgetter(0, -1):

from operator import truth, itemgetter
from itertools import groupby

[itemgetter(0,-1)([i for i,v in g]) for _, g in groupby(enumerate(a), key = lambda x: truth(x[1]))]
# [(0, 9), (10, 101), (102, 128), (129, 217), (218, 252), (253, 338), (339, 362), (363, 447), (448, 490), (491, 580), (581, 581)]
2
ACascarino 26 Фев 2018 в 11:17

Это ответ без внешней библиотеки:

pointer = 0
is_zero = True
result = []


def finder(p, is_z):
    while (a[p] == 0) is is_z:
        p += 1
        if p == len(a):
            return p
    return p


while pointer < len(a):
    tmp = finder(pointer, is_zero)
    result.append((pointer, tmp - 1))
    pointer = tmp
    is_zero = not is_zero
print(result)
1
Yakir Tsuberi 26 Фев 2018 в 11:53
import numpy as np 

unique, counts = np.unique(a, return_counts=True)
idx = tuple(zip(unique, counts))

Я думаю, что это будет работать для вас.

-2
DimKoim 26 Фев 2018 в 11:00