Многомерный массив в Python - PullRequest
8 голосов
/ 03 февраля 2009

У меня небольшая проблема с Java, которую я хочу перевести на Python. Для этого мне нужен многомерный массив. В Java это выглядит так:

double dArray[][][] = new double[x.length()+1][y.length()+1][x.length()+y.length()+3];
dArray[0][0][0] = 0;
dArray[0][0][1] = POSITIVE_INFINITY;

Дальнейшие значения будут создаваться в цикле bei и записываться в массив.

Как мне создать экземпляр массива?

PS: Умножение матриц не используется ...

Ответы [ 12 ]

18 голосов
/ 04 ноября 2008

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

arr = [[1,2],[3,4]]

дает двумерный массив. Доступ к строкам возможен как arr[i] для i в {0,..,len(arr}, но доступ к столбцам затруднен.

Если вы хотите добавить библиотечную зависимость, пакет NumPy - это то, что вам действительно нужно. Вы можете создать массив фиксированной длины из списка списков, используя:

import numpy
arr = numpy.array([[1,2],[3,4]])

Доступ к столбцам такой же, как и для списка списков, но доступ к столбцам прост: arr[:,i] для i в {0,..,arr.shape[1]} (количество столбцов).

На самом деле массивы NumPy могут быть n-мерными.

Пустые массивы могут быть созданы с помощью

numpy.empty(shape)

где shape - кортеж размера в каждом измерении; shape=(1,3,2) дает трехмерный массив с размером 1 в первом измерении, размером 3 во втором измерении и 2 в третьем измерении.

Если вы хотите хранить объекты в массиве NumPy, вы также можете сделать это:

 arr = numpy.empty((1,), dtype=numpy.object)
 arr[0] = 'abc'

Для получения дополнительной информации о проекте NumPy посетите домашнюю страницу NumPy .

13 голосов
/ 04 ноября 2008

Чтобы создать стандартный массив массивов Python произвольного размера:

a = [[0]*cols for _ in [0]*rows]

Доступ осуществляется так:

a[0][1] = 5 # set cell at row 0, col 1 to 5

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

a = [[0]*cols]*rows

, но при этом будет скопирован один и тот же массив столбцов в каждую строку, что приведет к нежелательному поведению. А именно:

>>> a[0][0] = 5
>>> print a[1][0]
5
11 голосов
/ 03 февраля 2009

Взгляните на numpy

вот фрагмент кода для вас

import numpy as npy

d = npy.zeros((len(x)+1, len(y)+1, len(x)+len(y)+3))
d[0][0][0] = 0 # although this is unnecessary since zeros initialises to zero
d[i][j][k] = npy.inf

Я не думаю, что вам нужно внедрять научное приложение, чтобы оправдать использование numpy. Это быстрее и гибче, и вы можете хранить практически все, что угодно. Учитывая это, я думаю, что, вероятно, лучше попытаться оправдать , а не , используя это. Есть законные причины, но это добавляет много и стоит очень мало, поэтому заслуживает рассмотрения.

P.S. Правильны ли длины вашего массива? Это выглядит как довольно своеобразная матрица ...

11 голосов
/ 03 февраля 2009

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

matrix = [[a,b],[c,d],[e,f]]

Если он должен быть динамичным, то он сложнее, почему бы не написать небольшой класс самостоятельно?

class Matrix(object):
    def __init__(self, rows, columns, default=0):
        self.m = []
        for i in range(rows):
            self.m.append([default for j in range(columns)])

    def __getitem__(self, index):
        return self.m[index]

Это можно использовать так:

m = Matrix(10,5)
m[3][6] = 7
print m[3][6] // -> 7

Я уверен, что можно было бы реализовать это намного эффективнее. :)

Если вам нужны многомерные массивы, вы можете либо создать массив и рассчитать смещение, либо использовать массивы в массивах в массивах, что может быть очень плохо для памяти. (Хотя может быть быстрее ...) Я реализовал первую идею, как это:

class Matrix(object):
    def __init__(self, *dims):
        self._shortcuts = [i for i in self._create_shortcuts(dims)]
        self._li = [None] * (self._shortcuts.pop())
        self._shortcuts.reverse()

    def _create_shortcuts(self, dims):
        dimList = list(dims)
        dimList.reverse()
        number = 1
        yield 1
        for i in dimList:
            number *= i
            yield number

    def _flat_index(self, index):
        if len(index) != len(self._shortcuts):
            raise TypeError()

        flatIndex = 0
        for i, num in enumerate(index):
            flatIndex += num * self._shortcuts[i]
        return flatIndex

    def __getitem__(self, index):
        return self._li[self._flat_index(index)]

    def __setitem__(self, index, value):
        self._li[self._flat_index(index)] = value

Можно использовать так:

m = Matrix(4,5,2,6)
m[2,3,1,3] = 'x'
m[2,3,1,3] // -> 'x'
10 голосов
/ 04 ноября 2008

Многомерные массивы немного мутные. Есть несколько причин для их использования и много причин, чтобы дважды подумать и использовать что-то еще, что более правильно отражает то, что вы делаете. [Подсказка. ваш вопрос был тонок по контексту ;-)]

Если вы занимаетесь математикой, используйте numpy.

Однако некоторые люди работали с языками, которые заставляют их использовать многомерные массивы, потому что это все, что у них есть. Если вам столько же лет, сколько мне (я начал программировать в 70-х годах), вы, возможно, помните времена, когда многомерные массивы были единственной структурой данных, которую вы имели. Или ваш опыт мог ограничить вас языками, в которых вам пришлось преобразовывать проблему в многомерные массивы.

Скажем, у вас есть коллекция n 3D очков. Каждая точка имеет значения x, y, z и времени. Это массив n x 4? Или массив 4 * n ? На самом деле, нет.

Поскольку каждая точка имеет 4 фиксированных значения, это более корректный список кортежей.

a = [ ( x, y, z, t ), ( x, y, z, t ), ... ]

Более того, мы могли бы представить это как список объектов.

class Point( object ):
    def __init__( self, x, y, z, t ):
        self.x, self.y, self.z, self.t = x, y, z, t

a = [ Point(x,y,x,t), Point(x,y,z,t), ... ]
5 голосов
/ 03 февраля 2009

Если вы в порядке, используя разреженные массивы, вы можете использовать dict для хранения ваших значений. Диктофоны Python позволяют вам использовать кортежи в качестве ключей, поэтому вы можете назначать и получать доступ к элементам «разреженного массива» (который здесь действительно является диктатом) следующим образом:

d = {}
d[0,2,7] = 123 # assign 123 to x=0, y=2, z=7
v = d[0,2,7]
4 голосов
/ 03 февраля 2009

Возможно, это не относится к вам, но если вы выполняете серьезную матричную работу, см. numpy

3 голосов
/ 04 ноября 2008

Для числовых данных Массивы Numpy :

>>> matrix1 = array(([0,1],[1,3]))
>>> print matrix1
[[0 1]
[1 3]]

Для общих данных (например, строк) вы можете использовать список списков, список кортежей, ...

matrix2 = [['a','b'], ['x','y']]
2 голосов
/ 04 февраля 2009

Вот быстрый способ создания вложенного 3-мерного списка, инициализированного нулями:

# dim1, dim2, dim3 are the dimensions of the array
a =[[[0 for _ in range(dim1)] for _ in range(dim2)] for _ in range(dim1) ]
a[0][0][0] = 1

это список списков списков, немного более гибкий, чем массив, вы можете сделать:

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

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

a[0] = "Ouch"
print a[0][0] #will print "O", since strings are indexable the same way as lists
print a[0][0][0] #will raise an error, since "O" isn't indexable

но если вам нужна производительность, тогда я согласен, что NumPy это путь.

Также остерегайтесь:

a = [[[0] * 5]*5]*5]

Если вы попробуете a[0][0][0]=7 на объекте выше, вы увидите, что с этим не так.

0 голосов
/ 29 сентября 2009

Легко, при использовании numpy:

b = ones((2,3,4)) # creates a 2x3x4 array containing all ones.

'единицы' можно заменить на 'нули'

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...