开发者

Python Multidimensional Array as a single List

Sure, you can have nested lists to represent multidimensional arrays, but that seems costly...

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

Is there some way to "encode" and "decode" the coordinate into a single number, and use that number to loo开发者_如何学Ckup the corresponding element?

[0, 1, 2, 3]

This needs to work with n-dimensions, not just two, and the best I could come up with for encoding is:

def getcellindex(self, location):
  cindex = 0
  cdrop = self.gridsize # where self.gridsize is the number of cells
  for index in xrange(self.numdimensions): # where self.numdimensions is the number of dimensions
    # where self.dimensions is a tuple of the different sizes of the corresponding dimension
    cdrop /= self.dimensions[index]
    cindex += cdrop * location[index]
  return cindex

There're probably ways to optimize this, but more importantly, how do I reverse the process? And, does this function work?


Are you avoiding the obvious answer (i.e. [[1, 2], [3, 4]]) because of concerns about its performance? If so and you're working with numberes, look at NumPy arrays. The best solution would be to not reinvent your own wheel.

Edit: If you do feel the need to do it your own way, you could follow a strided index scheme like NumPy, wihch might go something like this:

import operator
def product(lst):
    return reduce(operator.mul, lst, 1)

class MyArray(object):
    def __init__(self, shape, initval):
        self.shape = shape
        self.strides = [ product(shape[i+1:]) for i in xrange(len(shape)) ]
        self.data = [initval] * product(shape)

    def getindex(self, loc):
        return sum([ x*y for x, y in zip(self.strides, loc) ])

    def getloc(self, index):
        loc = tuple()
        for s in self.strides:
            i = index // s
            index = index % s
            loc += (i,)
        return loc

To be used as:

arr = MyArray((3, 2), 0)
arr.getindex((2, 1))
  -> 5
arr.getloc(5)
  -> (2, 1)


def getlocation(self, cellindex):
    res = []
    for size in reversed(self.dimensions):
        res.append(cellindex % size)
        cellindex /= size
    return res[::-1]

Or, for the full test case

class ndim:
    def __init__(self):
        self.dimensions=[8,9,10]
        self.numdimensions=3
        self.gridsize=8*9*10

    def getcellindex(self, location):
        cindex = 0
        cdrop = self.gridsize
        for index in xrange(self.numdimensions):
            cdrop /= self.dimensions[index]
            cindex += cdrop * location[index]
        return cindex

    def getlocation(self, cellindex):
        res = []
        for size in reversed(self.dimensions):
            res.append(cellindex % size)
            cellindex /= size
        return res[::-1]

n=ndim()
print n.getcellindex((0,0,0))
print n.getcellindex((0,0,1))
print n.getcellindex((0,1,0))
print n.getcellindex((1,0,0))

print n.getlocation(90)
print n.getlocation(10)
print n.getlocation(1)
print n.getlocation(0)


If you want fast arrays you may want to see numpy arrays which are pretty fast. Otherwise if you have dimensions n1, n2, n3, ...,nm, then you can encode a[i][j][k]...[r]: i * (product of (n2, n3...)) + j * (product of (n3, n4...)) + r. The reverse operation you have to get module of nm and that will be r, then you have to substract r and find module of nm*n(m-1) and so on.


A well known bijection:


from itertools import tee

def _basis(dimensions):
    # compute products of subtuple entries
    return tuple(reduce(lambda x,y: x*y, dimensions[:i]) for i in xrange(1, len(dimensions)+1))

def coordinate(n, dimensions):
    basis = _basis(dimensions)
    residues = [n % b for b in basis]
    it2, it1 = tee(basis)
    for x in it2:
        break
    return (residues[0],) + tuple((m2-m1)/b in m2, m1, b in zip(it2, it1, basis))

def number(c, dimensions):
    basis = _basis(dimensions)
    return sum(x*b for x, b in zip(c, basis))

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜