Python, преобразование списка индексов в срезы

Итак, у меня есть список индексов,

[0, 1, 2, 3, 5, 7, 8, 10]

и хотите преобразовать его в это,

[[0, 3], [5], [7, 8], [10]]

это будет работать на большом количестве индексов.

Кроме того, технически это не для фрагментов в python, инструмент, с которым я работаю, работает быстрее, когда задан диапазон, по сравнению с отдельными идентификаторами.

Шаблон основан на нахождении в диапазоне, подобно тому, как фрагменты работают в питоне. Таким образом, в примере 1 и 2 отбрасываются, потому что они уже включены в диапазон от 0 до 3. К 5 необходимо обращаться по отдельности, поскольку он не находится в диапазоне и т. д. Это более полезно, когда большое количество идентификаторов попасть в диапазон, например [0, 5000].


person Saebin    schedule 11.06.2012    source источник
comment
Каков ваш способ потерять одни числа и сгруппировать другие? Если ваша задача слишком сложна, то придумайте для этого упражнения меньшее здесь и подумайте, как распространить его на вашу проблему, когда вы знаете, как это работает! Просто давать вам совершенно общие советы, я думаю, вам не помогут.   -  person erikbwork    schedule 12.06.2012
comment
Ну, шаблон основан на том, чтобы быть в диапазоне, как срезы работают в питоне. Таким образом, в примере 1 и 2 отбрасываются, потому что они уже включены в диапазон от 0 до 3. К 5 необходимо обращаться по отдельности, поскольку он не находится в диапазоне и т. д. Это более полезно, когда большое количество идентификаторов попасть в диапазон, например [0, 5000].   -  person Saebin    schedule 12.06.2012


Ответы (4)


Поскольку вы хотите, чтобы код был быстрым, я бы не стал слишком причудливым. Прямой подход должен работать достаточно хорошо:

a = [0, 1, 2, 3, 5, 7, 8, 10]
it = iter(a)
start = next(it)
slices = []
for i, x in enumerate(it):
    if x - a[i] != 1:
        end = a[i]
        if start == end:
            slices.append([start])
        else:
            slices.append([start, end])
        start = x
if a[-1] == start:
    slices.append([start])
else:
    slices.append([start, a[-1]])

По общему признанию, это выглядит не очень хорошо, но я ожидаю, что лучшие решения, которые я могу придумать, будут работать хуже. (Я не делал тест.)

Вот немного более красивое, но более медленное решение:

from itertools import groupby
a = [0, 1, 2, 3, 5, 7, 8, 10]
slices = []
for key, it in groupby(enumerate(a), lambda x: x[1] - x[0]):
    indices = [y for x, y in it]
    if len(indices) == 1:
        slices.append([indices[0]])
    else:
        slices.append([indices[0], indices[-1]])
person Sven Marnach    schedule 11.06.2012
comment
Спасибо, работает хорошо... казалось бы, простая проблема, но поставила меня в тупик XD - person Saebin; 12.06.2012

Поскольку производительность является проблемой, используйте первое решение от @SvenMarnach, но вот забавный один вкладыш, разделенный на две строки! :D

>>> from itertools import groupby, count
>>> indices = [0, 1, 2, 3, 5, 7, 8, 10]
>>> [[next(v)] + list(v)[-1:]
     for k,v in groupby(indices, lambda x,c=count(): x-next(c))]
[[0, 3], [5], [7, 8], [10]]
person jamylak    schedule 12.06.2012

Ниже приведен простой код Python с numpy:

def list_to_slices(inputlist):
      """
      Convert a flatten list to a list of slices:
      test = [0,2,3,4,5,6,12,99,100,101,102,13,14,18,19,20,25]
      list_to_slices(test)
      -> [(0, 0), (2, 6), (12, 14), (18, 20), (25, 25), (99, 102)]
      """
      inputlist.sort()
      pointers = numpy.where(numpy.diff(inputlist) > 1)[0]
      pointers = zip(numpy.r_[0, pointers+1], numpy.r_[pointers, len(inputlist)-1])
      slices = [(inputlist[i], inputlist[j]) for i, j in pointers]
      return slices
person bougui    schedule 16.03.2017

person    schedule
comment
Мне нравится, как он работает с итерируемыми типами, и отлично работает в моем случае... но предполагает отсортированную последовательность. Такие вещи, как наборы, автоматически сортируют целые числа, но я не уверен, насколько этому можно доверять. - person Saebin; 12.06.2012
comment
@Saebin, да, это предполагает отсортированную последовательность, потому что это то, что вы использовали в своем примере. Вы можете легко использовать seq.sorted() для предварительной сортировки. set вообще не сортируется, если кажется, что это просто совпадение, вероятно, скорее с маленькими числами, чем с большими. - person Mark Ransom; 12.06.2012