Как скопировать один элемент списка по ссылке, а не по значению?

Допустим, у нас есть 2D-массив foo_arr:

foo_arr = [[None, None, None, None],
           [None, None, None, None],
           [None, None, None, None],
           [None, None, None, None]]

Теперь я хочу иметь доступ к 2D-массиву как из его строк, так и из его столбцов. Например, я могу просто сделать row_0 = foo_arr[0], и любые изменения в foo_arr[0] будут отражены в row_0; то есть если мы сделаем это:

row_0 = foo_arr[0]
foo_arr[0][0] = (0, 0)
# row_0 == [(0, 0), None, None, None]

Я также хочу иметь возможность делать это со столбцами. Например, я хочу что-то вроде column_0 = [foo_arr[0][0], foo_arr[1][0], foo_arr[2][0], foo_arr[3][0]], и когда я меняю foo_arr (или column_0), каждый из них должен видеть. Иллюстрация желаемого поведения:

column_0 = [foo_arr[i][0] for i in range(4)]
foo_arr[0][0] = (0, 0)
foo_arr[1][0] = (0, 1)
# Desired: column_0 == [(0, 0), (0, 1), None, None]
# Actual: column_0 == [None, None, None, None]

По сути, я бы хотел, чтобы это было написано на C:

int** foo_arr = malloc(sizeof(int*)*4);
for(int i=0; i<4; i++) {
    foo_arr[i] = malloc(sizeof(int)*4);
    for(int j=0; j<4; j++) {
        foo_arr[i][j] = -1; /* Using -1 here to represent None */
    }
}
int* row_0 = foo_arr[0];
int** column_0 = malloc(sizeof(int)*4);
for(int i=0; i<4; i++) {
    column_0[i] = &foo_arr[i][0]; /* Yes, technically the same as just doing foo_arr[i] for column 0 */
}
/* Changing the 2D array: */
foo_arr[0][0] = 0;
foo_arr[1][0] = 4;
foo_arr[2][0] = 8;
/* We should have:
   *column_0[0] == 0;
   *column_0[1] == 4;
   *column_0[2] == 8; */

Можно ли получить такое поведение в Python? Есть ли у numpy или других пакетов такое поведение? edit: я бы не хотел писать функцию-оболочку, которая просто извлекает столбец. Если я обрабатываю столбцы много раз, я не хочу генерировать новый список, представляющий столбец, каждый раз, когда я хочу работать со столбцами.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
61
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Итак, у вас есть очень сложный код, но все, что вам действительно нужно, это массив numpy:

import numpy as np

# foo_arr = np.array(
#     [
#         [None, None, None, None],
#         [None, None, None, None],
#         [None, None, None, None],
#         [None, None, None, None]
#     ]
# )
# or better:
foo_arr = np.empty((4, 4), dtype=object)

row_0 = foo_arr[0, :]
col_0 = foo_arr[:, 0]

foo_arr[1, 0] = (0, 0)
print(row_0, col_0)
Ответ принят как подходящий

Я не думаю, что есть прямой способ сделать это со списками 2D+. Но с numpy это тривиально:

foo_lst = [[None, None, None, None],
           [None, None, None, None],
           [None, None, None, None],
           [None, None, None, None]]

foo_arr = np.array(foo_lst, dtype=object)
foo_arr[:, 0] = np.arange(4)

Результат:

array([[0, None, None, None],                                                                                         
       [1, None, None, None],                                                                                
       [2, None, None, None],                                                                                
       [3, None, None, None]], dtype=object)

Если вы в основном будете иметь дело со столбцами list, вы можете рассмотреть возможность транспонирования:

lst2d = [[...], [...], ...]

lst2d_t = [list(col) for col in zip(*lst2d)]
# index the ith "column" like so: lst2d_t[col_no]

Но numpy предпочтительнее на данный момент.

Вы можете создать тип, который знает, где искать изменения:

class ListRef:
    def __init__(self, collection, index):
        self.collection = collection
        self.index = index
    def get(self):
        return self.collection[self.index]

    def __repr__(self):
        return str(self.get())
    
foo_arr = [[None, None, None, None],
           [None, None, None, None],
           [None, None, None, None],
           [None, None, None, None]]


column_0 = [ListRef(foo_arr[i], 0) for i in range(4)]
print(column_0)

foo_arr[0][0] = (0, 0)
foo_arr[1][0] = (0, 1)
print(column_0)

Выход:

[None, None, None, None]
[(0, 0), (0, 1), None, None]

Другие вопросы по теме