Создайте новый список из данного списка так, чтобы новый список мог отмечать последовательные повторения в данном списке - PullRequest
2 голосов
/ 17 апреля 2019

У меня длинный список (несколько сотен тысяч единиц) чисел, и я хочу создать новый список равного размера, чтобы выяснить места, где есть последовательные повторения чисел. Новый список будет иметь значения 0 и 1, так что для последовательных повторяющихся индексов новый список будет иметь 1, а для остальных индексов - 0.

Если есть что-то вроде столбца панд, которое также может быть полезным.

Пример заданного списка и результирующего массива. Список также может иметь значения с плавающей запятой.

given_array = [1, 2, 3, 5, 5, 5, 5, 0, -2, -4, -6, -8, 9, 9, 9]

result_array = [0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]

Ниже приведен небольшой рабочий пример моего кода.

import itertools    

def list_from_count(list_item):
    """
    Function takes an iterator and based on the length of the item
    returns 1 if length is 1 or list of 0 for length greater than 1
    """
    if len(list(list_item[1])) == 1:
        return 1
    else:
        return [0] * len(list(list_item[1]))

r0 = list(range(1,4))
r1 = [5]*4
r2 = list(range(0,-10,-2))
r3 = [9]*3
r = r0 + r1 + r2 + r3


gri = itertools.groupby(r)
res = list(map(list_from_count,gri))

print ("Result",'\n',res)

Результат

[1, 1, 1, [], 1, 1, 1, 1, 1, []]

Заранее спасибо!

Ответы [ 4 ]

3 голосов
/ 17 апреля 2019

Вы можете использовать itertools.groupby и выводить повторные 1 с, если длина группы больше 1:

from itertools import groupby

result_array = []
for _, g in groupby(given_array):
    size = sum(1 for i in g)
    if size == 1:
        result_array.append(0)
    else:
        result_array.extend([1] * size)

или с пониманием списка:

result_array = [i for _, g in groupby(given_array) for s in (sum(1 for i in g),) for i in ([0] if s == 1 else [1] * s)]

result_array становится:

[0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]
1 голос
/ 18 апреля 2019

Эта ситуация больше похожа на проблему кодирования длины прогона . Рассмотрим more_itertools.run_length:

С учетом

import more_itertools as mit


iterable = [1, 2, 3, 5, 5, 5, 5, 0, -2, -3, -6, -8, 9, 9, 9]

Код

result = [[0] if n == 1 else [1] * n for _, n in mit.run_length.encode(iterable)]
result
# [[0], [0], [0], [1, 1, 1, 1], [0], [0], [0], [0], [0], [1, 1, 1]]

Теперь просто сведите подсписки (как хотите) в один список:

list(mit.flatten(result))
# [0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]

подробности

mit.run_length.encode сжимает итерируемое, получая кортежи ( значение , # повторений ), например ::1010 *

list(mit.run_length.encode("abaabbba"))
# [('a', 1), ('b', 1), ('a', 2), ('b', 3), ('a', 1)]

Наше понимание игнорирует значение, использует повторы n и создает подсписки [0] и [1] * n.

Примечание: more_itertools - сторонний пакет. Установить через > pip install more_itertools.

1 голос
/ 17 апреля 2019

Вы используете len(list(list_item[1])) дважды.При первом использовании он обрабатывает все элементы итератора.Когда вы вызываете его во второй раз, итератор полностью израсходован, поэтому он возвращает 0, поэтому вы получаете список с нулевым элементом.

Вам нужно сохранить длину в переменной в первый раз:

def list_from_count(list_item):
    l = len(list(list_item[1]))
    if l == 1:
        return [0]
    else:
        return [1] * l

Вам также необходимо последовательно возвращать список из этой функции, затем вы можете объединить все результаты, чтобы не получать смесь чисел и подсписков.

res = []
for el in gri:
    res += list_from_count(el)
print(res)
0 голосов
/ 17 апреля 2019

Используйте оператор PANDAS shift для создания элемента со сдвигом вектора на 1. Сравните это с оригиналом. Это даст вам вектор значений True / False, показывающий, где элемент соответствует предыдущему. Запустите линейный поиск по этому списку, чтобы расширить один элемент спереди: измените [False, True] на [True, True]. Преобразование в int, и у вас есть список, который вы указали.

...