Как из двух массивов сделать двумерный python
Перейти к содержимому

Как из двух массивов сделать двумерный python

Программирование в «Эврике»

Теперь мы можем присваивать каждому элементу списка A новое значение. Например, мы можем сделать элемент A[0] также равным списку:

A[0]=range[3]

Теперь A будет равно [[0, 1, 2], 1, 2, 3, 4] , то есть объект A[0] будет списком [0, 1, 2] . В свою очередь, мы можем обращаться к отдельным элементам списка A[0] : A[0][0]==0 , A[0][1]==1 , A[0][2]==2 .

На практике часто приходится иметь дело с прямоугольными таблицами данных, также называемых двумерными массивами. Их можно представлять в виде списка из n элементов (строк), каждый из которых является списком из m элементов (столбцов). Тогда к отдельному элементу двумерного массива A можн обращаться, как A[i][j] , где i является номером строки, 0

Итак, создадим массив A из n=3 строк и m=5 столбцов:

n=3 m=5 A=range(n) # A является списком из n строк for i in range(n): A[i]=range(m) # Каждая строка является списком из m элементов
Заполнение массива

Теперь заполним массив нулями. Для этого нам понадобится два вложенных цикла: внешний цикл по всем строкам, а внутренний – по всем столбцам.

for i in range(n): for j in range(m): A[i][j]=0

Если мы захотим записать в массив таблицу умножения, присвоив элементу A[i][j] значение i*j , последнюю строку в этом примере нужно записать в виде A[i][j]=i*j .

Вывод массива на экран

Конечно, можно вывести массив A на экран одной командой print A , но тогда все элементы будут выведены в одну строку:

[[0, 0, 0, 0, 0], [0, 1, 2, 3, 4], [0, 2, 4, 6, 8]]

Но можно вывести массив в виде таблицы, так, чтобы каждая строка массива была выведена на одной строке, а внутри строки числа разделялись одним пробелом, то есть в виде:

A[0][0] A[0][1] A[0][2] A[0][3] A[0][4] A[1][0] A[1][1] A[1][2] A[1][3] A[1][4] A[2][0] A[2][1] A[2][2] A[2][3] A[2][4]

Для этого снова понадобятся два вложенных цикла. Один цикл по всем строкам, другой – по всем столбцам. В результате получаем:

for i in range(n): for j in range(m): print A[i][j], print

Обратите внимание на запятую, поставленную после инструкции print A[i][j] , необходимую для того, чтобы печать продолжалась на этой же строке. А вот инструкцию print без параметров для перехода на новую строку мы даем после завершения внутреннего цикла, то есть после вывода всей строки на экран. Вот что получится:

0 0 0 0 0 0 1 2 3 4 0 2 4 6 8
Считывание с клавиатуры

Теперь рассмотрим проблему считывания массива с клавиатуры в таком же виде. Проблема заключается в том, что функция input позволяет считать только одно значение, записанное в строке и выдаст ошибку при считывании набора чисел, разделенных пробелами. А функция raw_input сможет считать строку как единое целое вместе со всеми пробелами. Разбить строку на отдельные выражения, разделенные пробелами можно при помощи метода split() . Этот метод применяется к строке и возвращает список подстрок, состоящих из непробельных символов и разделенных пробелами. То есть если применить метод split к строке ‘1 2 3’ , то получится список из 3 строк: [‘1’, ‘2’, ‘3’] . Таким образом, мы можем разбить каждую входную строку на отдельные подстроки, а затем преобразовать эти подстроки к числовому виду при помощи функции int . В результате получаем следующий код (предполагается, что массив A из n строк и m столбцов уже создан):

for i in range(n): # Цикл по всем строкам s=raw_input() # Считали строку в переменную s s=s.split() # Разбили s на слова и записали их в виде списка for j in range(m): A[i][j]=int(s[j]) # Элементу A[i][j] присваиваем значение s[j]
Общий пример программы

Теперь объединим это все в одну программу, которая считывает с клавиатуры числа n и m (заданные в одной строке), затем создает массив из n строк и m столбцов, затем считывает его с клавиатуры построчно, затем увеличивает каждый элемент массива на 1, наконец, печатает результат:

# Считываем размеры массива s=raw_input() s=s.split() n=int(s[0]) m=int(s[1]) # Создаем массив A=range(n) for i in range(n): A[i]=range(m) # Считываем массив с клавиатуры for i in range(n): s=raw_input() s=s.split() for j in range(m): A[i][j]=int(s[j]) # Увеличиваем все элементы на 1 for i in range(n): for j in range(m): A[i][j]=A[i][j]+1 # Выводим массив на экран for i in range(n): for j in range(m): print A[i][j], print
Сложный пример обработки массива

Пусть дан квадратный массив из n строк и n столбцов. Необходимо элементам, находящимся на главной диагонали проходящей из левого верхнего угла в правый нижний (то есть тем элементам A[i][j] , для которых i==j ) присвоить значение 1 , элементам, находящимся выше главной диагонали – значение 0, элементам, находящимся ниже главной диагонали – значение 2. То есть получить такой массив (пример для n==4 ):

1 0 0 0 2 1 0 0 2 2 1 0 2 2 2 1

Рассмотрим несколько способов решения этой задачи. Элементы, которые лежат выше главной диагонали – это элементы A[i][j] , для которых ij . Таким образом, мы можем сравнивать значения i и j и по ним определять значение A[i][j] . Получаем следующий алгоритм:

for i in range(n): for j in range(n): if ij: A[i][j]=2 else: A[i][j]=1

Данный алгоритм плох, поскольку выполняет одну или две инструкции if для обработки каждого элемента. Если мы усложним алгоритм, то мы сможем обойтись вообще без условных инструкций.

Сначала заполним главную диагональ, для чего нам понадобится один цикл:

for i in range(n): A[i][i]=1

Затем заполним значением 0 все элементы выше главной диагонали, для чего нам понадобится в каждой из строк с номером i присвоить значение элементам A[i][j] для j = i+1 , . n-1 . Здесь нам понадобятся вложенные циклы:

for i in range(n): for j in range(i+1,n): A[i][j]=0

Аналогично присваиваем значение 2 элементам A[i][j] для j = 0 , . i-1 :

for i in range(n): for j in range(0,i): A[i][j]=2

Можно также внешние циклы объединить в один и получить еще одно, более компактное решение:

for i in range(n): for j in range(0,i): A[i][j]=2 A[i][i]=1 for j in range(i+1,n): A[i][j]=0
Форматирование чисел при выводе

Допустим, мы заполним массив таблицей умножения: A[i][j]=i*j как в примере в начале раздела. Если мы теперь попробуем вывести этот массив на экран, разделяя элементы в строке одним пробелом, то из-за того, что числа имеют различную длину столбцы таблицы окажутся неровными:

0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 0 2 4 6 8 10 12 14 16 18 0 3 6 9 12 15 18 21 24 27

Для того, чтобы получить ровные столбцы необходимо, выводить числа так, чтобы одно выводимое число имело длину, например, ровно в 2 символа, а «лишние» позиции были бы заполнены пробелами.

0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 0 2 4 6 8 10 12 14 16 18 0 3 6 9 12 15 18 21 24 27

Без лишних комментариев покажем, как в программе указать, что целое число x нужно выводить так, чтобы оно занимало ровно две позиции: print «%2d» % x . Здесь, естественно, можно заменить значение x на то значение, которое необходимо напечатать, а число 2 на любую другую ширину поля.

Итак, для печати ровной таблицы умножения можно воспользоваться следующим кодом:

for i in range(n): for j in range(m): print «%2d» % A[i][j],

Двумерные массивы

Часто в задачах приходится хранить прямоугольные таблицы с данными. Такие таблицы называются матрицами или двумерными массивами. В языке программирования Питон таблицу можно представить в виде списка строк, каждый элемент которого является в свою очередь списком, например, чисел. Например, создать числовую таблицу из двух строк и трех столбцов можно так:

A = [ [1, 2, 3], [4, 5, 6] ]

Здесь первая строка списка 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 i in range(len(A)): for j in range(len(A[i]): print(A[i][j], end = ' ') print()

То же самое, но циклы не по индексу, а по значениям списка:

for row in A: for elem in row: print(elem, end = ' ') print()

Естественно для вывода одной строки можно воспользоваться методом join :

for row in A: print(' '.join(list(map(str, row))))

Используем два вложенных цикла для подсчета суммы всех чисел в списке:

S = 0 for i in range(len(A)): for j in range(len(A[i])): S += A[i][j]

Или то же самое с циклом не по индексу, а по значениям строк:

S = 0 for row in A: for elem in row: S += elem

Создание списка

Пусть даны два числа: количество строк n и количество столбцов m . Необходимо создать список размером n × m , заполненный нулями.

Очевидное решение оказывается неверным:

A = [ [0] * m ] * n

В этом легко убедиться, если присвоить элементу A[0][0] значение 1 , а потом вывести значение другого элемента A[1][0] — оно тоже будет равно 1! Дело в том, что [0] * m возвращает ccылку на список из m нулей. Но последующее повторение этого элемента создает список из n элементов, которые являются ссылкой на один и тот же список (точно так же, как выполнение операции B = A для списков не создает новый список), поэтому все строки результирующего списка на самом деле являются одной и той же строкой.

Таким образом, двумерный список нельзя создавать при помощи операции повторения одной строки. Что же делать?

Первый способ: сначала создадим список из n элементов (для начала просто из n нулей). Затем сделаем каждый элемент списка ссылкой на другой одномерный список из m элементов:

A = [0] * n for i in range(n): A[i] = [0] * m

Другой (но похожий) способ: создать пустой список, потом n раз добавить в него новый элемент, являющийся списком-строкой:

A = [] for i in range(n): A.append([0] * m)

Ввод списка

Пусть программа получает на вход двумерный массив, в виде n строк, каждая из которых содержит m чисел, разделенных пробелами. Как их считать? Например, так:

A = [] for i in range(n): A.append(list(map(int, input().split())))

Или, без использования сложных вложенных вызовов функций:

A = [] for i in range(n): row = input().split() for i in range(len(row)): row[i] = int(row[i]) A.append(row)

Сложный пример обработки массива

Пусть дан квадратный массив из n строк и n столбцов. Необходимо элементам, находящимся на главной диагонали, проходящей из левого верхнего угла в правый нижний (то есть тем элементам A[i][j] , для которых i==j ) присвоить значение 1 , элементам, находящимся выше главной диагонали – значение 0, элементам, находящимся ниже главной диагонали – значение 2. То есть получить такой массив (пример для n==4 ):

1 0 0 0 2 1 0 0 2 2 1 0 2 2 2 1

Рассмотрим несколько способов решения этой задачи. Элементы, которые лежат выше главной диагонали – это элементы A[i][j] , для которых ij . Таким образом, мы можем сравнивать значения i и j и по ним определять значение A[i][j] . Получаем следующий алгоритм:

for i in range(n): for j in range(n): if i < j: A[i][j] = 0 elif i >j: A[i][j] = 2 else: A[i][j] = 1

Данный алгоритм плох, поскольку выполняет одну или две инструкции if для обработки каждого элемента. Если мы усложним алгоритм, то мы сможем обойтись вообще без условных инструкций.

Сначала заполним главную диагональ, для чего нам понадобится один цикл:

for i in range(n): A[i][i] = 1

Затем заполним значением 0 все элементы выше главной диагонали, для чего нам понадобится в каждой из строк с номером i присвоить значение элементам A[i][j] для j = i+1 , . n-1 . Здесь нам понадобятся вложенные циклы:

for i in range(n): for j in range(i + 1, n): A[i][j] = 0

Аналогично присваиваем значение 2 элементам A[i][j] для j = 0 , . i-1 :

for i in range(n): for j in range(0, i): A[i][j] = 2

Можно также внешние циклы объединить в один и получить еще одно, более компактное решение:

for i in range(n): for j in range(0, i): A[i][j] = 2 A[i][i] = 1 for j in range(i + 1, n): A[i][j] = 0

А вот такое решение использует операцию повторения списков для построения очередной строки списка. i -я строка списка состоит из i чисел 2 , затем идет одно число 1 , затем идет n-i-1 число 0 :

for i in range(n): A[i] = [2] * i + [1] + [0] * (n - i - 1)

Упражнения

A: Максимум

Найдите индексы первого вхождения максимального элемента. Выведите два числа: номер строки и номер столбца, в которых стоит наибольший элемент в двумерном массиве. Если таких элементов несколько, то выводится тот, у которого меньше номер строки, а если номера строк равны то тот, у которого меньше номер столбца.

3 4
0 3 2 4
2 3 5 5
5 1 2 3

Создать из двух списков один двумерный

Я пробовал использовать функцию zip() — z = zip(nums,links) , но она меня не устраивает, т.к в дальнейшем может понадобиться добавить значения в каждый из рядов или новый ряд. Интересует также, как можно упорядочить в готовом 3ем списке элементы по убыванию значений чисел, когда я пытался это сделать функцией sorted() z = sorted(z, key=lambda tup:(tup[0])) результат был примерно таким: 10,123,11,1101,21,2222,200 — т.е числа отсортировались, но не по значению, а по первой цифре числа.

Отслеживать
47.9k 17 17 золотых знаков 56 56 серебряных знаков 100 100 бронзовых знаков
задан 20 окт 2017 в 18:57
11 5 5 бронзовых знаков

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

По поводу сортировки, вы усложняете себе жизнь — не нужно ни какой key-функции, просто

z = sorted(list3) 
sorted([[13, "aaa"], [100, "bbb"], [1, "ccc"], [3, "ddd"]]) 
[[1, 'ccc'], [3, 'ddd'], [13, 'aaa'], [100, 'bbb']] 

На счет проблемы с zip() я тоже не понял.

Отслеживать
ответ дан 9 мая 2020 в 3:29
16.2k 4 4 золотых знака 19 19 серебряных знаков 30 30 бронзовых знаков

Обычно делаю это так:

>>> links = [" ", " ", " "] >>> nums = [1,123, 13] >>> list3 = [list(x) for x in zip(nums, links)] >>> list3 [[1, ' '], [123, ' '], [13, ' ']] >>> sorted(list3) [[1, ' '], [13, ' '], [123, ' ']] 

Отслеживать
51.6k 200 200 золотых знаков 61 61 серебряный знак 242 242 бронзовых знака
ответ дан 10 июн 2020 в 20:21
21 1 1 бронзовый знак

По поводу сортировки:

In [15]: from operator import itemgetter In [16]: list3 = [[123, 'text_1'],[321,'text_2'], [110, 'text_3'], [11, 'text_4']] In [17]: sorted(list3, key=itemgetter(0)) Out[17]: [[11, 'text_4'], [110, 'text_3'], [123, 'text_1'], [321, 'text_2']] 

На счет проблемы с zip() не совсем понятно.

Отслеживать
ответ дан 20 окт 2017 в 19:23
Pavel Durmanov Pavel Durmanov
5,726 3 3 золотых знака 22 22 серебряных знака 44 44 бронзовых знака

Странно, но почему-то проблема с сортировкой сохраняется, хотя код from operator import itemgetter links = [‘txt1’, ‘txt2’, ‘txt3’, ‘txt4’] nums = [123, 13123, 1090, 10] z = zip(nums, links) z = sorted(z, key=itemgetter(0)) print(z) в новом скрипте отрабатывает как и должен. Может ли это как-то быть связано с тем, что сортировка происходит в созданной мной функции parse(), а затем уже эта функция вызывается n раз(n соответствует количеству страниц, которые необходимо отпарсить) уже в функции main()? На счет zip пока точно не уверен, просто что-то пошло не так)

20 окт 2017 в 20:12

Почему-то проблема сохраняется, даже если сортировать просто список с числами-вот результат print() [‘1791’, ‘1553’, ‘1193’, ‘1705’, ‘1468’, ‘1265’, ‘1076’, ‘1593’, ‘1175’, ‘1144’, ‘165’, ‘196’, ‘134’, ‘194’, ‘2734’, ‘2339’, ‘2703’, ‘257’, ‘299’, ‘273’, ‘277’, ‘287’, ‘217’, ‘270’, ‘273’, ‘298’, ‘211’, ‘281’, ‘255’, ‘279’, ‘251’, ‘3949’, ‘3938’, ‘348’, ‘368’, ‘326’, ‘368’, ‘399’, ‘383’, ‘355’, ‘313’, ‘480’, ‘426’, ‘454’, ‘489’, ‘436’, ‘429’, ‘500’, ‘568’, ‘555’, ‘544’, ‘529’, ‘578’, ‘525’, ‘668’, ‘605’, ‘600’, ‘617’, ‘768’, ‘710’, ‘799’, ‘747’, ‘837’, ‘872’, ‘828’, ‘827’, ‘969’, ‘900’, ‘977’]

20 окт 2017 в 20:40

Вообщем, получилось отсортировать список с числами таким способом: people.sort(key=lambda people: int(people.split()[0])) . Но! Если попытаться сделать это для переменной z, которая является кортежем двух списков, то появится ошибка.

Объединение и разделение массивов

На предыдущем занятии мы познакомились со способами изменения форм массивов. Здесь мы узнаем как реализуются операции объединения и разделения массивов. Для этой задачи в NumPy реализованы специальные функции, которые мы сейчас и рассмотрим.

Функции hstack и vstack

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

a = np.array([(1, 2), (3, 4)]) b = np.array([(5, 6), (7, 8)])

Их можно объединить как по горизонтали, так и по вертикали, с помощью функций:

np.hstack([a, b]) # объединение по оси axis1 (размерность 2x4) np.vstack([a, b]) # объединение по оси axis0 (размерность 4x2)

Примеры работы этих двух функций представлены на рисунке ниже:

Эти же операции можно выполнять и с многомерными массивами. Например, определим два трехмерных массива:

a = np.fromiter(range(18), dtype='int32') b = np.fromiter(range(18, 36), dtype='int32') a.resize(3, 3, 2) b.resize(3, 3, 2)

И выполним функции:

c = np.hstack([a, b]) # размерность 3x6x2 d = np.vstack([a, b]) # размерность 6x3x2

Как видите, здесь произошло формальное объединение по оси axis1 в функции hstack и по оси axis0 в функции vstack.

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

Аналогичным образом происходит объединение и одномерных массивов:

a = np.fromstring('1 2 3 4', sep = ' ') b = np.fromstring('5 6 7 8', sep = ' ')

И при выполнении:

np.hstack([a, b])

array([1., 2., 3., 4., 5., 6., 7., 8.])

А во втором случае:

np.vstack([a, b])

результатом будет двумерный массив:

Функции column_stack и row_stack

Давайте теперь зададимся вопросом: как объединить наши два одномерных массива столбцами? Чтобы результат выглядел вот так:

Для этого хорошо подходит функция column_stack():

np.column_stack([a, b]) # формирование массива 4x2

Если с ее помощью объединять двумерные и многомерные массивы, то она будет давать тот же результат, что и функция hstack().

Другая аналогичная функция row_stack(), в принципе, делает то же самое, что и функция vstack() заметных отличий здесь нет. Ее можно использовать так:

np.row_stack([a, b]) # матрица 2x4

Функция concatenate

Для объединения массивов вдоль строго определенной оси можно воспользоваться функцией concatenate(). Например, возьмем два трехмерных массива:

a = np.arange(1, 13) b = np.arange(13, 26) a.resize(3, 3, 2) b.resize(3, 3, 2)

И объединим их по каждой из осей:

c0 = np.concatenate([a, b], axis=0) # размерность 6x3x2 c1 = np.concatenate([a, b], axis=1) # размерность 3x6x2 c2 = np.concatenate([a, b], axis=2) # размерность 3x3x4

Объекты r_ и c_

Еще один способ объединения и создания массивов – это использование специальных объектов r_ и c_. Например, объект r_ создает копии массивов, следующими способами:

np.r_[ [1, 2, 3], 4, 5] # список + дополнительные элементы np.r_[ 1:9, 90, 100] # срез + два элемента np.r_[ np.array([1,2,3]), np.array([4,5,6])] # объединение двух массивов np.r_[ [(1,2,3), (4,5,6)], [(7,8,9)] ] # объединение двумерного и одномерного списков

По аналогии работает и второй объект c_, только объединение выполняется по второй оси axis1:

np.c_[1:5] np.c_[ [1, 2, 3], [4, 5, 6]] np.c_[ [(1,2,3), (4,5,6)], [[7],[8]] ]

Разделение массивов

Массивы в NumPy можно не только объединять, но и разделять. Для этого существуют специальные функции hsplit и vsplit. Рассмотрим их работу на простых примерах. Пусть имеется одномерный массив из 10 элементов:

a = np.arange(10)

И мы хотим разделить его на две равные части. Это реализуется с помощью функции hsplit:

np.hsplit(a, 2)

которая возвращает список из двух массивов. Второй параметр 2 указывает число частей, на которые делится исходный массив. Причем, деление выполняется по горизонтали. Если в нашем примере указать 3 части, то возникнет ошибка:

np.hsplit(a, 3) # ошибка 10 на 3 нацело не делится

так как 10 элементов нельзя равномерно разбить на 3 части.

Также ошибка будет и при разбиении этого массива по вертикали:

np.vsplit(a, 2) # ошибка: нет вертикальной оси

так как массив имеет одну горизонтальную ось. Чтобы вторая функция сработала, преобразуем массив a в вектор столбец:

a.shape = 10, -1 # вектор-столбец

а, затем, разобьем по вертикали:

np.vsplit(a, 2)

На выходе получим два одномерных массива длиной 5 элементов.

Эти же функции можно использовать и с многомерными массивами, например, так:

a = np.arange(12) a.resize(2, 6) # двумерный массив 2x6 np.hsplit(a, 2) # разбиение по горизонтали np.vsplit(a, 2) # разбиение по вертикали

Функция array_split

Рассмотренные функции выполняют разбиение или по первой оси axis0 или по второй оси axis1. Но что если нам нужно выполнить разбиение по произвольной оси многомерного массива? Для этого существует функция array_split(). Ее работа аналогична рассмотренным выше функциям, только дополнительно указывается ось разбиения. Например:

a = np.arange(18) a.resize(3, 3, 2) np.array_split(a, 2, axis=2) np.array_split(a, 3, axis=0) np.array_split(a, 3, axis=1)

Видео по теме

#1. Пакет numpy — установка и первое знакомство | NumPy уроки

#2. Основные типы данных. Создание массивов функцией array() | NumPy уроки

#3. Функции автозаполнения, создания матриц и числовых диапазонов | NumPy уроки

#4. Свойства и представления массивов, создание их копий | NumPy уроки

#5. Изменение формы массивов, добавление и удаление осей | NumPy уроки

#6. Объединение и разделение массивов | NumPy уроки

#7. Индексация, срезы, итерирование массивов | NumPy уроки

#8. Базовые математические операции над массивами | NumPy уроки

#9. Булевы операции и функции, значения inf и nan | NumPy уроки

#10. Базовые математические функции | NumPy уроки

#11. Произведение матриц и векторов, элементы линейной алгебры | NumPy уроки

#12. Множества (unique) и операции над ними | NumPy уроки

#13. Транслирование массивов | NumPy уроки

© 2023 Частичное или полное копирование информации с данного сайта для распространения на других ресурсах, в том числе и бумажных, строго запрещено. Все тексты и изображения являются собственностью сайта

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *