@13_nastya_13

Как создать из списка подсписки и посчитать частоту повторения?

Не уверенна, что задала правильно вопрос, но постараюсь описать проблему тут. Мне нужно написать функцию, которая берет список, например data = [0, 1, 1, 2, 1, 3, 4, 4, 5, 4], ищет период повторения, сравнивая элементы в подсписках между собой. То есть в начале должен разделится список на n-число подсписков, начиная с n=3, наш список не делится на 3 одинаковых части, значит берем 4, опять не делится, берем 5, делим наш список по пять элементов = [0, 1, 1, 2, 1] [3, 4, 4, 5, 4] и теперь нужно проверить последовательность(либо же индексы), в этом случае одинаково, следовательно функция должна возвращать значение 5. И вот еще один пример, возьмем тот же список только с 15 элементами [0, 1, 1, 2, 1, 3, 4, 4, 5, 4, 5, 6, 6, 3, 6], сделаем опять проверку, на этот раз делится на три то есть [0,1,1] [2,1,3] [4,4,5][4,5,6][6,3,6] у них нету ничего общего, дели дальше, на 4 не делится, берем 5: [0, 1, 1, 2, 1] [3, 4, 4, 5, 4] [5, 6, 6,3,6] последовательность у них одинакова, значит нам подходит деление на 5 и функция возвращает результат 5. Надеюсь кто-то что-то сможет понять из того что написано выше, помогите пожалуйста...
  • Вопрос задан
  • 942 просмотра
Решения вопроса 1
@o5a
Насколько понял задачу, нужно постепенно перебирая равные куски списка найти наибольшие, при которых все куски будут иметь одинаковые "уникальные индексы".

Изменил код на поиск наименьшего периода.

# рассчитываем "уникальные индексы" списка
def unique_index(arr):
    elems = []
    for e in arr:
        if e not in elems:
            elems.append(e)
    indexes = {v:i for i,v in enumerate(elems)}
    result = [indexes[e] for e in arr]
    return result

# собственно функция поиска максимального числа
def find_min_period(arr):
    for i in range(3, len(arr)//2+1):
        # если делится на части
        if not len(arr)%i:
            # "уникальный индекс" 1-го куска
            unique = unique_index(arr[:i])
            # делим на части и проверяем, чтобы для каждой "уникальный индекс" был одинаковый
            for j in range(i, len(arr), i):
                # при первом несовпадении сразу переходим к следующему делителю
                if unique != unique_index(arr[j:j+i]):
                    break
            else:
                # если все куски оказались с одинаковыми "уникальными индексами" выдаем наше число элементов
                return i
    return None

print(find_min_period([0, 1, 1, 2, 1, 3, 4, 4, 5, 4, 5, 6, 6, 3, 6]))
# 5
print(find_min_period([0, 1, 1, 2, 1, 1, 3, 4, 4, 40, 4, 4]))
# 3
print(find_min_period([0, 1, 1, 2, 1, 1, 3, 4, 4, 4, 4, 12]))
# None
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
adugin
@adugin Куратор тега Python
Вариант с numpy:
import numpy as np

a = [0, 1, 1, 2, 1, 3, 4, 4, 5, 4]

N = len(a)
a = np.array(a)

for n in range(3, N):
    if N % n == 0:
        b = a.reshape(-1, n)
        b = np.diff(b, axis=1)
        if np.all(b == b[0]):
            print(n)

Вариант без внешних библиотек:
from operator import sub

a = [0, 1, 1, 2, 1, 3, 4, 4, 5, 4]

N = len(a)

for n in range(3, N):
    if N % n != 0:
        continue
    matrix = list(zip(*[iter(a)]*n))
    for i, row in enumerate(matrix):
        matrix[i] = map(sub, row[1:], row[:-1])
    transposed = zip(matrix)
    row_to_set = map(set, transposed)
    set_to_len = map(len, row_to_set)
    if len(set(set_to_len)) == 1:
        print(n)
Ответ написан
@bbkmzzzz
В лоб, еще можно крутить, но работает. Вроде)
def get_list_part_count(lst: list, start_divider):
    # ищем наименьшее количество частей списка
    ln = len(lst)
    while True:
        if ln % start_divider != 0:
            start_divider += 1
        else:
            break
    return start_divider


def find_max_item_val_in_dict(dc: dict):
    # ищем максимальное значение элемента словаря
    # предполагаем, что отрицательных чисел в наших списках не будет
    max_val = -1
    result_item = None
    for key in dc:
        if dc[key] > max_val:
            max_val = dc[key]
            result_item = key
    return result_item


def split_list_to_parts(lst, part_count):
    # делим список на части, заданные в параметре part_count
    part_len = int(len(lst) / part_count)  # длина одной части
    y = []  # результирующий список
    for multiplier in range(1, part_count + 1):
        #  заполняем наш список срезами исходного
        y.append(lst[(part_len * multiplier) - part_len:part_len * multiplier])
    return y


def find_periodic_seq(seq, start_divider):
    #  получаем наш разделенный список
    splitted_list = split_list_to_parts(seq, get_list_part_count(seq, start_divider))
    #  тут будут храниться наши последовательности
    counters = []

    # нужно больше циклов!!!
    # пробегаем по нашему расщепенцу
    for sub_list in splitted_list:

        dc = {}
        for element in sub_list:
            #  заполняем словарь dc данными, сколько раз каждый элемент встречается в последовательности
            #  count намеренно не использовал
            try:
                dc[element] += 1
            except KeyError:
                dc[element] = 1
        # находим элемент, котрый максимально часто встречается в последовательности
        max_item = find_max_item_val_in_dict(dc)

        lst = []
        #  собираем индексы, на которых находятся наши элементы и запихиваем в список lst
        for pos, element in enumerate(sub_list):
            if element == max_item:
                lst.append(pos)
        #  список со списками индексов максимально часто повторяющихся элементов, предварительно разбитого списка!
        counters.append(lst)

    #  если длина списка == количеству повторений первого элемента -> наш список содержит одинаковые элементы
    if len(counters) == counters.count(counters[0]):
        return counters[0]
    else:
        return None


if __name__ == '__main__':
    #  не улетаем в небеса и ограничиваем бесконечный цикл
    stop_cycles = 10
    current_cycles = 1

    #  исходный список
    lst = [0, 1, 1, 2, 1, 3, 4, 4, 5, 4, 5, 6, 6, 3, 6]

    #  минимальное количество элементов в каждой части при дроблении списка на части
    start_divider = 3
    while True:
        if current_cycles > stop_cycles:
            print(f'Can not find sequence with {current_cycles} cycles, stopping :(')
            break
        
        #  вызываем нашу основную функцию
        result = find_periodic_seq(lst, start_divider)
        if not result:
            #  если ничего не нашлось - увеличиваем минимальную длину части на 1
            start_divider += 1
        else:
            print(f'seq was founded with {current_cycles} cycles! {result}')
            break
Ответ написан
@domanskiy
Нужно использовать модуль collections
from collections import Counter

c = Counter(mylist)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы