Возьмите 2D-список любых четных измерений и верните список, содержащий количество вещей для каждой сетки 2 X 2 (Python)

1

Я пытаюсь сделать функцию, которая примет список, такой как:

l = [["A", 1, 2, 3, 4, 5],
     ["A", "A", 2, 3, 4, 5],
     [1, 2, 3, 4, 5, 5],
     ["A", "A", "A", "A", "A", "A"],
     ["A", 3, "A", 4, "A", "A"],
     [1, 3, 5, "A", 5, "A"]
     ]

и ключ, например "A". И предоставит список, содержащий int, в зависимости от того, сколько раз KEY появляется в 2D-списке в каждой ячейке 2x2. Так, например, функция

def count_in_grids(l, key):

вернусь

[3, 0, 0, 2, 2, 2, 1, 2, 3]

Пока у меня действительно плохой код, который я написал. У меня обычно возникают проблемы с управлением 2D-списками. Поскольку это фактически назначение, мне не разрешено использовать какую-либо библиотеку. Если кто-то может помочь мне понять и написать это, я буду глубоко этому благодарен.

Мой дрянной код, который я написал до сих пор:

def countInGrids(l, thing):
new_list = []  # created a final list that will be returned
count = 0
for line in range(0, len(l), 2):  # Access lines
    for el in range(0, line, 2):  # Access elements
        #count + count() of all elements in line[el] to line[el+1], 
        move 2 lines down and repeat.
        count += line[line[el]:line[el]+1].count(thing) 
        count += line+1[line[el]:line[el]+1].count(thing)

        new_list.append(count)
print(new_list)
return new_list

OUTPUT: строка 63, в countInGrids count + = line [line [el]: строка [el] +1]. Count (вещь) TypeError: объект 'int' не является индексируемым

PS: Если кому-то интересно, это мой первый семестр CS Lab

  • 0
    for line in range(0, len(l), 2): результате line становится целым числом. Но в вашем цикле вы пытаетесь проиндексировать его как массив или список. Это сообщение об ошибке здесь.
  • 0
    Поскольку сегодня я целый день перередактировал этот метод, я упустил такую простую ошибку. Я пытался запустить этот метод, используя для x в списке ранее, но все еще не работал, потому что я действительно не понимал, как это сделать.
Теги:
arrays
list
matrix

2 ответа

3
Лучший ответ

Это, вероятно, немного неуклюжий, но перечислить понимание всегда можно.

def countInGrid(grid, key):
    return [sum([v[i:i+2].count(key) for v in grid[j:j+2]])
            for j in range(0, len(grid), 2) for i in range(0, len(grid[0]), 2)]

Исходя из этого, то, что он использует для создания сетки 2x2, является [v[i:i+2] for v in grid[j:j+2]. Это не очень эффективная операция, если вы делаете это во весь список списков несколько раз, но быстро записываете.

Чтобы подсчитать ключ, он сначала учитывается в каждой строке с помощью .count(key), а затем добавляет его для каждой из двух строк в вашей сетке 2x2, используя sum().

Последняя строка - это то, как вы выбираете, какую сетку 2x2 вы хотите посмотреть. Он указывает, где вы начнете и где закончите. Порядок i и j важен, если вы не хотите итерации по столбцам, а затем по строкам.

В понимании списка в основном есть все следующие небольшие компоненты, завернутые в более строгий синтаксис.

def count_row(v, key):
    return v.count(key)

def count_grid(grid, key):
    return sum(count_row(v, key) for v in grid)

def get_nxn(grid, i, j, n=2):
    return [v[i:i+n] for v in grid[j:j+n]]

def iter_block_row(grid, j):
    for i in range(0, len(grid[0]), 2):
        yield get_nxn(grid, i, j)

def iter_grid(grid):
    for j in range(0, len(grid), 2):
        # In Python 3.3+, use
        # yield from iter_block_row(grid, j)
        for g in iter_block_row(grid, j):
            yield g

def count_in_grid(grid, key):
    return [count_grid(g, key) for g in iter_grid(grid)]

Размышление о больших проблемах, состоящих из небольших частей, помогает сделать их управляемыми с любым опытом. Также полезно видеть, что вам не нужны какие-либо дополнительные синтаксические сахара и языковые трюки для достижения той же цели чистым способом.

Обратите внимание, что срезы в get_nxn() неэффективны. Это один из способов разложить проблему (и я думаю, что это самый простой способ мыслить концептуально), но это НЕ самый эффективный.

Обновление Я ошибался в работе get_nxn(). Похоже, что куски списков в Python не копируют данные, даже в Python 2. 7+. Операция get_nxn() выполняется в постоянное время по отношению к размеру grid, и при этом происходит быстрое постоянное время.

  • 0
    Ух ты! Вы сделали это менее чем за минуту. Большое спасибо, я действительно ценю это, особенно потому что это должно сегодня. Я действительно так плох в CS, хотя .... У меня ушел час, чтобы НЕ найти решение; (
  • 0
    Программирование требует практики. Ключ состоит в том, чтобы разбить вещи на маленькие, легко понятные части. Через секунду я отредактирую ответ с лучшим стилем, который будет легче понять.
Показать ещё 1 комментарий
1

Заманчиво попытаться найти решение с нарезкой и пониманием сразу с места в карьер, но я думаю, что риск путаницы достаточно высок, чтобы было нормально начать с наивного решения.

Первый шаг - найти все углы суб-квадратов:

1 . 2 . 3 .
. . . . . .
4 . 5 . 6 .
. . . . . .
7 . 8 . 9 .
. . . . . .

Это подсчет вложенного цикла на 2, где угловая ячейка находится в (row, col).

Учитывая подквадр, пересечение его ячеек - это еще одна пара вложенных циклов с шагом 1:

1 2 x . x .
3 4 . . . .
x . x . x .
. . . . . .
x . x . x .
. . . . . .

Здесь каждый элемент находится в (row + i, col + j) где i и j - шаги внутреннего цикла.

После этого, это вопрос написания условного теста и добавления счетчика для каждого под-квадрата в список результатов.

Наконец, добавьте размер шага в качестве параметра по умолчанию, чтобы увеличить повторное использование.

Объединяя это:

def count_in_grids(l, key, size=2):
    result = []

    for row in range(0, len(l), size):
        for col in range(0, len(l[row]), size):
            result.append(0)

            for i in range(size):
                for j in range(size):
                    if key == l[row+i][col+j]:
                        result[-1] += 1

    return result

print(count_in_grids(l, "A"))

Здесь нужно повторить тест.

  • 0
    Не быть слишком педантичным, поскольку он достаточно хорошо выражает более длительное время работы для больших объектов, но накладные расходы на нарезку будут только дополнительным линейным фактором. У вас все еще будет время выполнения полинома низкого порядка. Кроме того, я просто углубился в это, и фрагменты списка - это представления в исходном списке; кроме постоянного числа поисков указателей, однако они реализовали это, нет никаких дополнительных затрат при получении большого количества перекрывающихся фрагментов.
  • 0
    Я не уверен в деталях сложности времени нарезки за пределами «линейной», но я был бы рад изучить бенчмаркинг или провести дополнительные исследования, и мне было бы любопытно увидеть ваши источники. Я большой поклонник лаконичного Pythonic-кода, но в этом случае мне кажется очевидным, что OP нашел бы работающий и, несомненно, эффективный алгоритм намного быстрее, используя базовые циклы, чем сразу переходя к нарезке и подсчету. Позже я могу увидеть рефакторинг для трехслойного списка компоновок, но заслуга здесь не кажется мне такой очевидной или поучительной, как в других случаях.
Показать ещё 6 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню