Как создать вложенные списки python
Здесь первая строка списка a[0] является списком из чисел [1, 2, 3] . То есть a[0][0] == 1 , значение a[0][1] == 2 , a[0][2] == 3 , a[1][0] == 4 , a[1][1] == 5 , a[1][2] == 6 .
Для обработки и вывода списка, как правило, используют два вложенных цикла. Первый цикл перебирает номер строки, второй цикл бежит по элементам внутри строки. Например, вывести двумерный числовой список на экран построчно, разделяя числа пробелами внутри одной строки, можно так:
Однажды мы уже пытались объяснить, что переменная цикла for в Питоне может перебирать не только диапазон, создаваемый с помощью функции range() , но и вообще перебирать любые элементы любой последовательности. Последовательностями в Питоне являются списки, строки, а также некоторые другие объекты, с которыми мы пока не встречались. Продемонстрируем, как выводить двумерный массив, используя это удобное свойство цикла for :
Естественно, для вывода одной строки можно воспользоваться методом join() :
Используем два вложенных цикла для подсчета суммы всех чисел в списке:
Или то же самое с циклом не по индексу, а по значениям строк:
2. Создание вложенных списков
Пусть даны два числа: количество строк n и количество столбцов m . Необходимо создать список размером n × m , заполненный нулями.
Очевидное решение оказывается неверным:
В этом легко убедиться, если присвоить элементу a[0][0] значение 5 , а потом вывести значение другого элемента a[1][0] — оно тоже будет равно 5. Дело в том, что [0] * m возвращает ccылку на список из m нулей. Но последующее повторение этого элемента создает список из n элементов, которые являются ссылкой на один и тот же список (точно так же, как выполнение операции b = a для списков не создает новый список), поэтому все строки результирующего списка на самом деле являются одной и той же строкой.
В визуализаторе обратите внимание на номер id у списков. Если у двух списков id совпадает, то это на самом деле один и тот же список в памяти.
Таким образом, двумерный список нельзя создавать при помощи операции повторения одной строки. Что же делать?
Первый способ: сначала создадим список из n элементов (для начала просто из n нулей). Затем сделаем каждый элемент списка ссылкой на другой одномерный список из m элементов:
Другой (но похожий) способ: создать пустой список, потом n раз добавить в него новый элемент, являющийся списком-строкой:
Но еще проще воспользоваться генератором: создать список из n элементов, каждый из которых будет списком, состоящих из m нулей:
В этом случае каждый элемент создается независимо от остальных (заново конструируется список [0] * m для заполнения очередного элемента списка), а не копируются ссылки на один и тот же список.
3. Ввод двумерного массива
Пусть программа получает на вход двумерный массив в виде n строк, каждая из которых содержит m чисел, разделенных пробелами. Как их считать? Например, так:
Или, без использования сложных вложенных вызовов функций:
Можно сделать то же самое и при помощи генератора:
4. Пример обработки двумерного массива
Пусть дан квадратный массив из n строк и n столбцов. Необходимо элементам, находящимся на главной диагонали, проходящей из левого верхнего угла в правый нижний (то есть тем элементам a[i][j] , для которых i==j ) присвоить значение 1 , элементам, находящимся выше главной диагонали – значение 0, элементам, находящимся ниже главной диагонали – значение 2. То есть необходимо получить такой массив (пример для n==4 ):
Рассмотрим несколько способов решения этой задачи. Элементы, которые лежат выше главной диагонали – это элементы a[i][j] , для которых i<j , а для элементов ниже главной диагонали i>j . Таким образом, мы можем сравнивать значения i и j и по ним определять значение A[i][j] . Получаем следующий алгоритм:
Данный алгоритм плох, поскольку выполняет одну или две инструкции if для обработки каждого элемента. Если мы усложним алгоритм, то мы сможем обойтись вообще без условных инструкций.
Сначала заполним главную диагональ, для чего нам понадобится один цикл:
Затем заполним значением 0 все элементы выше главной диагонали, для чего нам понадобится в каждой из строк с номером i присвоить значение элементам a[i][j] для j = i+1 , . n-1 . Здесь нам понадобятся вложенные циклы:
Аналогично присваиваем значение 2 элементам a[i][j] для j = 0 , . i-1 :
Можно также внешние циклы объединить в один и получить еще одно, более компактное решение:
А вот такое решение использует операцию повторения списков для построения очередной строки списка. i -я строка списка состоит из i чисел 2 , затем идет одно число 1 , затем идет n-i-1 число 0 :
А можно заменить цикл на генератор:
5. Вложенные генераторы двумерных массивов
Для создания двумерных массивов можно использовать вложенные генераторы, разместив генератор списка, являющегося строкой, внутри генератора всех строк. Напомним, что сделать список из n строк и m столбцов можно при помощи генератора, создающего список из n элементов, каждый элемент которого является списком из m нулей:
Но при этом внутренний список также можно создать при помощи, например, такого генератора: [0 for j in range(m)] . Вложив один генератор в другой, получим вложенные генераторы:
Но если число 0 заменить на некоторое выражение, зависящее от i (номер строки) и j (номер столбца), то можно получить список, заполненный по некоторой формуле.
Например, пусть нужно задать следующий массив (для удобства добавлены дополнительные пробелы между элементами):
В этом массиве n = 5 строк, m = 6 столбцов, и элемент в строке i и столбце j вычисляется по формуле: a[i][j] = i * j .
8. Списки¶
Список (англ.: list) есть упорядоченный набор значений, где каждое значение доступно по индексу. Значения, входящие в список, называются элементами.
Списки похожи на строки, так как строки тоже являются упорядоченными наборами элементов — символов. Но в отличие от строк, элементы списка могут быть любых типов. Списки и строки, а также другие типы, являющиеся упорядоченными наборами, называются последовательностями.
8.2. Списочные значения¶
Есть несколько способов создать новый список, простейший из них — заключить элементы в квадратные скобки, [ и ] :
В первом примере у нас список из четырех целых чисел. Во втором — список из трех строк. Элементы списка не обязательно относятся к одному типу. Следующий список содержит строку, число с плавающей точкой, целое число и. еще один список:
Список внутри другого списка называют вложенным.
Наконец, список может вовсе не содержать элементов. Такой список называют пустым и обозначают [] .
В логическом выражении пустой список, так же, как 0 или пустая строка, считается ложью:
Мы можем присваивать списочные значения переменным и передавать списки в качестве аргументов при вызове функций:
8.3. Доступ к элементам¶
Для доступа к элементам списка используется тот же оператор [] , что и для доступа к символам строки. Выражение в квадратных скобках задает индекс. Не забывайте, что индексы начинаются с 0:
В качестве индекса можно использовать любое целочисленное выражение:
Если попытаться получить доступ к несуществующему элементу, то получим ошибку выполнения:
Если индекс отрицательный, то счет идет от конца списка:
Выражение numbers[-1] дает последний элемент списка, numbers[-2] — второй от конца, а элемента numbers[-3] не существует.
Часто в качестве индекса используется переменная цикла.
Этот цикл while считает от 0 до 4. Когда переменная цикла i становится равна 4, условие становится ложным и цикл завершается. Таким образом, тело цикла выполняется для i со значениями 0, 1, 2 и 3.
В каждой итерации переменная i используется как индекс для списка, чтобы вывести i -тый элемент. Этот прием называется обход списка.
8.4. Длина списка¶
Функция len возвращает длину списка, то есть, количество элементов в списке. В качестве верхней границы в цикле удобно использовать возвращаемое этой функцией значение, а не константу. При этом, если размер списка изменится, вам не придется просматривать программу и вносить изменения во все циклы, работающие с этим списком; они будут работать корректно со списком любого размера:
В последней итерации i равно len(horsemen) - 1 , то есть, индексу последнего элемента списка. Когда i становится равным len(horsemen) , условие цикла становится ложным и тело цикла не выполняется. И это правильно, поскольку len(horsemen) недопустимый для данного списка индекс.
Хотя список может содержать другой список, вложенный список считается одним элементом. Длина этого списка равна 4:
8.5. Проверка вхождения в список¶
Оператор in проверяет вхождение элемента в последовательность и дает в результате логическое значение. Мы уже использовали его со строками, но он также работает со списками и другими последовательностями:
Поскольку ‘pestilence’ входит в список horsemen , то оператор in возвращает True . Поскольку ‘debauchery’ не входит в список, in возвращает False .
Используя not вместе с in , можно проверить, что элемент не является элементом списка:
8.6. Операции над списками¶
Оператор + конкатенирует списки:
Оператор * повторяет элементы списка заданное число раз:
В первом примере 0 повторяется четыре раза. Во втором три раза повторяются элементы 1, 2, 3 .
8.7. Срезы списков¶
Мы выполняли срезы строк, но срезы также работают для списков:
8.8. Функция range ¶
В программировании часто требуются списки последовательных целых чисел, и Python предоставляет простой способ для их создания:
Функция range принимает два аргумента и возвращает список целых, начиная от числа, заданного первым аргументом, и до числа, заданного вторым аргументом, не включая последнее.
Можно вызывать range и по-другому. При вызове с единственным аргументом функция возвращает список, начинающийся с 0:
Третий аргумент, если он указан, задает шаг между соседними значениями в списке. Получим список чисел от 1 до 10 с шагом 2:
Если шаг задан отрицательным числом, то начальное число должно быть больше конечного:
Иначе результатом будет пустой список:
8.9. Списки изменяемы¶
В отличие от строк, списки изменяемы. Это означает, мы можем изменять их элементы. Используя оператор [] в левой части присваивания, можно избирательно обновить один из элементов:
Оператор [] может использоваться со списком в любом месте выражения. Если он появляется слева от оператора присваивания, он изменяет элемент списка. В приведенном примере первый элемент списка fruit изменяется с 'banana' на 'pear' , а последний — с 'quince' на 'orange' . Присваивание отдельному элементу не работает для строк:
Но работает для списков:
Используя срез, можно изменить несколько элементов сразу:
Можно также удалить элементы из списка, присвоив им пустой список:
А можно добавить элементы в список, втиснув их в пустой срез в нужном месте:
8.10. Удаление списка¶
Удаление элементов с помощью присваивания срезов довольно вычурно, и потому чревато ошибками. Python предлагает альтернативный способ, более легкий для чтения и понимания, и, к тому же, более универсальный.
del удаляет элемент из списка:
Как и следовало ожидать, del работает с отрицательными индексами, и генерирует ошибку выполнения, если заданный индекс выходит за границы разрешенного диапазона.
С del можно использовать срез:
8.11. Объекты и значения¶
Выполним предложения присваивания:
Теперь мы знаем, что и a и b указывают на строку "banana" . Но мы не можем сказать, указывают ли они на одну и ту же строку.
Есть два варианта:
В первом случае a и b указывают на два разных объекта с одинаковыми значениями. Во втором случае они ссылаются на один и тот же объект. Объект — это что-то, с чем может быть связано имя переменной.
У каждого объекта имеется уникальный идентификатор, который можно получить с помощью функции id . Отобразив идентификаторы объектов, на которые указывают a и b , мы узнаем, связаны ли эти переменные с одним и тем же объектом:
Мы два раза получили один и тот же идентификатор, а это значит, что Python создал только одну строку, и обе переменные, a и b , связаны с ней. Вы, вероятно, получите другое значение идентификатора.
Интересно, что списки ведут себя иначе. Если создать два списка, то мы получим два объекта:
На диаграмме это выглядит так:

Переменные a и b ссылаются на разные объекты, имеющие одинаковые значения.
8.12. Альтернативные имена¶
Поскольку переменные ссылаются на объекты, то, если мы присвоим одну переменную другой, обе переменные будут ссылаться на один и тот же объект:
На диаграмме это выглядит так:

Поскольку два разных имени, a и b , связаны с одним и тем же списком, будем называть их альтернативными именами. Изменения, сделанные с использованием одного имени, оказывают влияние и на другое:
Хотя такое поведение может быть полезным, иногда оно оказывается нежелательным. Вообще говоря, лучше избегать альтернативных имен, работая с изменяемыми объектами. А вот для неизменяемых объектов альтернативные имена не представляют никаких проблем. Поэтому Python создает альтернативные имена для строк, когда представляется случай сэкономить память компьютера.
8.13. Клонирование списков¶
Если нужно изменить список и при этом сохранить копию оригинального списка, то понадобится сделать копию самого списка, а не ссылки на него. Этот процесс иногда называют клонированием.
Простейший способ клонировать список — воспользоваться оператором среза:
Получение любого среза списка a приводит к созданию нового списка. В данном случае срез включает весь список.
Теперь можно изменять список b , не беспокоясь об a :
8.14. Списки и циклы for ¶
Цикл for также работает со списками. Синтаксис такой:
Это предложение эквивалентно следующему фрагменту кода:
Цикл for более лаконичен, поскольку мы можем обойтись без переменной цикла i . Вот рассмотренный выше цикл, переписанный с помощью for .
Он читается почти по-английски: для (каждого) horseman (англ.: всадник) в (списке) horsemen (англ.: всадники) напечатать horseman.
Любое списочное выражение может быть использовано в цикле for :
В первом примере выводятся все числа, кратные 3, между 0 и 19. Во втором примере выражается энтузиазм по поводу разных видов фруктов.
Поскольку списки изменяемы, часто выполняется обход списка с изменением каждого из его элементов. Следующий пример возводит в квадрат все числа в списке от 1 до 5 :
Подумайте над выражением range(len(numbers)) и разберитесь, как оно работает. В данном случае нам нужно как значение, так и индекс элемента списка для того, чтобы мы могли присвоить ему новое значение.
Такой прием довольно распространен в программировании, поэтому Python предлагает более красивый способ реализовать его:
Здесь функция enumerate в каждой итерации возвращает очередной индекс и связанное с ним значение. Еще один пример того, как работает enumerate :
8.15. Списочные параметры¶
При передаче списка в качестве аргумента передается ссылка на список, а не его копия. А поскольку списки изменяемы, то изменение параметра внутри функции означает также и изменение аргумента. Например, функция ниже принимает список в качестве аргумента и умножает каждый элемент списка на 2:
Если поместить функцию double_stuff в файл ch08.py , то сможем так протестировать ее:
Параметр a_list и переменная things являются альтернативными именами одного и того же объекта.
Если функция модифицирует списочный параметр, изменения будут видны в вызывающем коде.
8.16. Чистые и модифицирующие функции¶
Функции, которые принимают списки как аргументы и изменяют эти списки в ходе выполнения, называются модифицирующими, а изменения, которые они делают, называются побочным эффектом.
Чистая функция не производит побочных эффектов. Все ее связи с вызывающей программой сводятся к параметрам, которых она не изменяет, и возвращаемому значению. Вот чистая функция double_stuff :
Эта версия double_stuff не изменяет своих аргументов:
При использовании чистой функции double_stuff , для изменения things вам понадобится присвоить возвращаемое значение things :
8.17. Какая функция лучше?¶
Все, что можно сделать с помощью модифицирующих функций, может быть сделано и при помощи чистых функций. На самом деле, некоторые языки программирования поддерживают только чистые функции. Есть мнение, что программы, использующие только чистые функции, быстрее разрабатывать и в них закрадывается меньше ошибок. И все же, иногда модифицирующие функции удобны, а в отдельных случаях программы с чистыми функциями менее эффективны.
Вообще, мы рекомендуем писать чистые функции всегда, когда это разумно, и прибегать к модифицирующим только в случаях, когда их использование дает несомненное преимущество.
8.18. Вложенные списки¶
Вложенный список — это список, являющийся элементом другого списка. В следующем списке элемент с индексом 3 есть вложенный список:
Если ввести nested[3] , то получим [10, 20] . Извлечь элемент из вложенного списка можно за два шага:
А можно объединить эти два шага в выражение:
Оператор квадратная скобка вычисляется слева направо, так что это выражение берет 3-й элемент списка nested и извлекает из него 1-ый элемент.
8.19. Матрицы¶
Вложенные списки часто используют для того, чтобы представлять матрицы. Например, матрицу

можно представить так:
matrix есть список из трех элементов, в котором каждый элемент задает строку матрицы. Можно получить целую строку матрицы, как обычно:
Также можно извлечь отдельный элемент матрицы, используя два индекса:
Первый индекс выбирает строку, а второй — столбец. Хотя этот способ представления матриц самый распространенный, он не является единственным. Его вариацией является список столбцов вместо списка строк. Позднее мы увидим более радикальную альтернативу, использующую словарь.
8.20. Разработка через тестирование¶
Разработка через тестирование (англ.: Test-driven development, TDD) — это практика разработки программ, в которой программа создается серией небольших итераций, в каждой из которых сначала пишутся автоматические тесты, а затем код, реализующий тестируемую функциональность. От итерации к итерации растет реализованная и оттестированная функциональность.
Продемонстрируем разработку через тестирование с помощью доктестов. Скажем, нам нужна функция, которая создает матрицу с rows строк и columns столбцов, принимая аргументы для rows и columns .
Сначала подготовим тест для этой функции в файле matrices.py :
Выполнив скрипт, видим, что тест не прошел:
Тест не проходит, поскольку тело функции не содержит ничего, кроме строки в тройных кавычках, и поэтому возвращает None . Наш тест требует, чтобы функция возвращала матрицу 3 x 5, заполненную нулями.
Правила разработки через тестирование говорят, что для начала нужно написать самый простой вариант, который бы удовлетворял тест. Так что, в этом случае, просто вернем ожидаемый результат:
Теперь при выполнении скрипта тест успешно проходит, но наша реализация make_matrix всегда возвращает один и тот же результат, а это явно не то, что имелось в виду. В качестве мотивации дальнейших улучшений добавим тест:
Как и следовало ожидать, тест не проходит:
Этот процесс называется разработкой через тестирование, потому что код пишется только тогда, когда имеется тест, который не проходит. Мотивированные последним тестом, теперь напишем более общее решение:
Это решение, похоже, работает, поскольку тесты проходят. Однако, начав пользоваться новой функцией, быстро обнаружим баг:
Мы хотели присвоить значение 7 элементу во второй строке и третьем столбце, но, вместо этого, значение 7 получили все элементы третьего столбца!
По размышлении становится ясно, что в нашем текущем решении каждая строка матрицы — всего лишь ссылка на один и тот же список. Это определенно не то, что нам нужно. Приступая к исправлению бага, сначала напишем тест, демонстрирующий наличие этого бага:
Теперь, имея тест, который демонстрирует баг в программе, мы должны найти лучшее решение:
Процесс разработки через тестирование имеет ряд преимуществ. Этот процесс:
- заставляет конкретно думать о задаче, которую нужно решить, прежде чем пытаться ее решить,
- поощряет разбивать сложные задачи на более мелкие и простые, и пошагово приближаться к решению задачи в целом,
- дает набор автоматических тестов для программы, облегчая внесение в нее изменений и дополнений в дальнейшем.
8.21. Строки и списки¶
В Python есть функция list , которая принимает значение некоторой последовательности как аргумент и создает список из ее элементов.
Также существует функция str , которая берет любое значение Python как аргумент и возвращает его строковое представление.
Как видно из последнего примера, с помощью str не удается соединить вместе элементы списка символов. Это можно сделать с помощью функции join из модуля string :
Две очень полезные функции модуля string имеют дело со списками строк. Функция split разбивает строку на слова, возвращая список слов. По умолчанию считается, что слова отделяются друг от друга одним или более пробельными символами:
Необязательный аргумент позволяет указать, какие символы считать разделителями слов. В следующем примере в качестве разделителя указана последовательность двух символов ai :
Заметьте, что ai не попадает в список.
Функция string.join делает обратное функции string.split . Она принимает два аргумента: список строк и разделитель, который будет разделять элементы списка в результирующей строке.
8.22. Глоссарий¶
8.23. Упражнения¶
Напишите цикл, который обходит список
и выводит длину каждого элемента. Что происходит, когда вы передаете целое число функции len ? Замените 1 на 'one' и выполните вашу программу снова.
Создайте файл ch08e02.py следующего содержания:
Добавляйте следующие наборы доктестов в докстроку в начале файла и пишите код Python, который обеспечит прохождение доктестов. Добавляйте по одному набору доктестов за один раз.
Вложенные списки Python
Элементами списка Python могут быть списки. В результате получаем вложенные списки или списки списков. Аналог — матрицы второго порядка. Пример списка из двух элементов приведен ниже. Но, каждый из этих элементов тоже список, но уже состоящий из трех элементов.
Доступ к элементам вложенных списков можно получить с помощью индексов. Ниже приведены примеры.
В Python в списках можно использовать отрицательные индексы.
Пример перебора всех элементов вложенного списка — используются вложенные циклы. В этом примере также показано, что вложенные в список списки могут быть разной длины.
Можно также использовать метод join для перебора.
Дальше показано как можно создавать вложенные списки.
Еще один способ создания вложенных списков: создать пустой список, а затем в него добавлять списки.
Lesson 9
Двумерные списки (массивы)
1. Вложенные списки: обработка и печать
Первый элемент a здесь — a[0] — это список чисел [1, 2, 3] . Первый элемент этого нового списка — a[0][0] == 1 ; кроме того, a[0][1] == 2 , a[0][2] == 3 , a[1][0] == 4 , a[1][1] == 5 , a[1][2] == 6 .
Для обработки двумерного массива обычно используются вложенные циклы. Первый цикл повторяется через номер строки, второй цикл проходит через элементы внутри строки. Например, так вы показываете двумерный численный список на экране по строкам, разделяя числа пробелами:
Мы уже пытались объяснить, что переменная for-loop в Python может выполнять итерацию не только по range() , но обычно по всем элементам любой последовательности. Последовательности в Python — это списки и строки (и некоторые другие объекты, которые мы еще не встретили). Посмотрите, как вы можете печатать двумерный массив, используя эту удобную функцию цикла for :
Естественно, для вывода одной строки вы можете использовать метод join() :
Так вы можете использовать 2 вложенных цикла для вычисления суммы всех чисел в двумерном списке:
Или то же самое с итерацией элементами, а не переменными i и j :
2. Вложенные списки: создание
Предположим, что указаны два числа: число строк n и количество столбцов m . Вы должны создать список размером n × m , заполненный, скажем, нулями.
Очевидное решение кажется неправильным:
Это можно легко увидеть, если вы установите значение a[0][0] на 5 , а затем распечатаете значение a[1][0] — оно также будет равно 5. Причина в том, что [0] * m возвращает только ссылку на список из m нулей, но не список. Последующее повторение этого элемента создает список из n элементов, все ссылки на один и тот же список (как и операция b = a для списков не создает новый список), поэтому все строки в результирующем списке на самом деле одинаковы строка.
Используя наш визуализатор, отслеживайте идентификатор списков. Если два списка имеют одинаковый номер id, это фактически тот же список в памяти.
Таким образом, двумерный список не может быть создан просто путем повторения строки. Что делать.
Возможный способ: вы можете создать список из n элементов (например, из n нулей), а затем сделать каждый из элементов ссылкой на другой одномерный список из m элементов:
Другой (но похожий) способ: создать пустой список, а затем append к нему новый элемент n раз (этот элемент должен быть списком длины m ):
Но самый простой способ — использовать генератор, создавая список из n элементов, каждый из которых представляет собой список из m нулей:
В этом случае каждый элемент создается независимо от других. Список [0] * m n раз помечается как новый, и копирование ссылок не происходит.
3. Как вы вводите двумерный массив?
Скажем, программа принимает входной двумерный массив в виде n строк, каждый из которых содержит m чисел, разделенных пробелами. Как заставить программу читать ее? Пример того, как вы можете это сделать:
Или, не используя сложные вложенные вызовы:
Вы можете сделать то же самое с генераторами:
4. Обработка двумерного массива: пример
Предположим, вам задан квадратный массив (массив из n строк и n столбцов). Предположим, вы должны установить элементы главной диагонали, равные 1 (т. Е. Те элементы a[i][j] для которых i==j ), чтобы установить элементы выше, чем диагональ, равная 0, и установить элементы ниже этой диагонали, равной 2. То есть вам нужно создать такой массив (пример для n==4 ): (В этом случае вы можете сделать это вручную, установив a[0][0] = 1 , a[0][1] = 0 и т. Д., Но вы не будете делать это вручную для массивов из 100 строк и 100 столбцов , что часто бывает.)
Мы стремимся показать вам несколько способов решения этой проблемы. Во-первых, обратите внимание, что элементы, лежащие над главной диагональю, — это элементы a[i][j] для которых i<j , а для элементов ниже главной диагонали i>j . Таким образом, мы можем сравнить значения i и j , определяющие значение a[i][j] . Мы получаем следующий алгоритм:
Этот алгоритм медленный: он использует два цикла и для каждой пары (i,j) выполняет одну или две команды if . Если мы усложним алгоритм, мы сможем сделать это без условного оператора.
Сначала заполните основную диагональ, для которой нам понадобится один цикл:
Затем заполните нулями все элементы над главной диагональю. Чтобы сделать это, для каждой строки с номером i вам нужно присвоить значение a[i][j] для j = i+1 , . n-1 . Для этого вам нужны вложенные циклы:
По аналогии, для j = 0 , . i-1 задайте элементы a[i][j] равными 2 :
Вы можете комбинировать весь этот код и получить другое решение:
Вот еще одно решение, которое повторяет списки для создания следующих строк списка. i строка списка состоит из i чисел 2 , за которым следует одно целое число 1 , за которым следуют ni-1 нули: