2012-07-13 56 views
2

我正在尝试将我已经构建到python环境中的一些Matlab库。到目前为止,我面临的最大问题是基于索引规范的数组动态分配。例如,使用MATLAB,键入以下内容:Python动态数组分配,Matlab风格

x = [1 2]; 
x(5) = 3; 

会导致:

x = [ 1  2  0  0  3] 

换句话说,我没有事先知道的(X),还是其内容的大小。数组必须根据我提供的索引实时定义。

在Python中,尝试以下操作:

from numpy import * 
x = array([1,2]) 
x[4] = 3 

会导致以下错误:IndexError:索引越界。在变通办法增加阵列中的循环,然后分配所需的值:

from numpy import * 
x = array([1,2]) 

idx = 4 
for i in range(size(x),idx+1): 
    x = append(x,0) 

x[idx] = 3 
print x 

它的工作原理,但它是不是很方便,它有可能成为n维arrays.I虽然有关子类ndarray非常繁琐实现我的目标,但我不确定它是否会起作用。有人知道更好的方法吗?


感谢您的快速回复。我不知道有关setitem方法(我对Python相当新)。我简单地覆盖了ndarray类如下:

import numpy as np 

class marray(np.ndarray): 

    def __setitem__(self, key, value): 

     # Array properties 
     nDim = np.ndim(self) 
     dims = list(np.shape(self)) 

     # Requested Index 
     if type(key)==int: key=key, 
     nDim_rq = len(key) 
     dims_rq = list(key) 

     for i in range(nDim_rq): dims_rq[i]+=1   

     # Provided indices match current array number of dimensions 
     if nDim_rq==nDim: 

      # Define new dimensions 
      newdims = [] 
      for iDim in range(nDim): 
       v = max([dims[iDim],dims_rq[iDim]]) 
       newdims.append(v) 

      # Resize if necessary 
      if newdims != dims: 
       self.resize(newdims,refcheck=False) 

     return super(marray, self).__setitem__(key, value) 

它的作品就像一个魅力!但是,我需要修改上面的代码,使得setitem允许改变维数以下这个请求:

a = marray([0,0]) 
a[3,1,0] = 0 

不幸的是,当我尝试使用这种numpy的功能

self = np.expand_dims(self,2) 

返回的类型是numpy.ndarray而不是主要 .marray。任何想法,如果我可以强制执行那些numpy函数输出marray如果提供marray作为输入?我认为这应该是可行的使用array_wrap,但我永远无法找到如何。任何帮助,将不胜感激。

+0

你'append'-IN-循环算法需要二次方时间,所以对于大型数组来说它会变得非常慢。 – 2012-07-13 14:44:25

+0

把它作为一个机会来摆脱所有的特定数组重新分配;) – sebastian 2013-11-14 14:49:24

+0

a)如果你不打算有稀疏值,即你想要顺序设置它们,你可以像np.fromiter一样。 b)如果你仍然打算使用子类ndarray,这篇文章应该清楚为什么这个类型不被保留,以及如何修复它http://docs.scipy.org/doc/numpy-1.10.1/user/basics.subclassing .html – Erik 2016-06-19 19:59:32

回答

3

Dynamic list that automatically expands冒用更新我的旧回答的自由。想这应该做你最需要什么/想

class matlab_list(list): 
    def __init__(self): 
     def zero(): 
      while 1: 
       yield 0 
     self._num_gen = zero() 

    def __setitem__(self,index,value): 
     if isinstance(index, int): 
      self.expandfor(index) 
      return super(dynamic_list,self).__setitem__(index,value) 

     elif isinstance(index, slice): 
      if index.stop<index.start: 
       return super(dynamic_list,self).__setitem__(index,value) 
      else: 
       self.expandfor(index.stop if abs(index.stop)>abs(index.start) else index.start) 
      return super(dynamic_list,self).__setitem__(index,value) 

    def expandfor(self,index): 
      rng = [] 
      if abs(index)>len(self)-1: 
       if index<0: 
        rng = xrange(abs(index)-len(self)) 
        for i in rng: 
         self.insert(0,self_num_gen.next()) 
       else: 
        rng = xrange(abs(index)-len(self)+1) 
        for i in rng: 
         self.append(self._num_gen.next()) 

# Usage 
spec_list = matlab_list() 
spec_list[5] = 14 
3

这是不是你想要相当的,但是...

x = np.array([1, 2]) 

try: 
    x[index] = value 
except IndexError: 
    oldsize = len(x) # will be trickier for multidimensional arrays; you'll need to use x.shape or something and take advantage of numpy's advanced slicing ability 
    x = np.resize(x, index+1) # Python uses C-style 0-based indices 
    x[oldsize:index] = 0 # You could also do x[oldsize:] = 0, but that would mean you'd be assigning to the final position twice. 
    x[index] = value 

>>> x = np.array([1, 2]) 
>>> x = np.resize(x, 5) 
>>> x[2:5] = 0 
>>> x[4] = 3 
>>> x 
array([1, 2, 0, 0, 3]) 

由于卖场如何numpy的数据线下罩(尽管创建数组时可以指定是否存储row-major或column-major),但多维数组在这里非常棘手。

>>> x = np.array([[1, 2, 3], [4, 5, 6]]) 
>>> np.resize(x, (6, 4)) 
array([[1, 2, 3, 4], 
     [5, 6, 1, 2], 
     [3, 4, 5, 6], 
     [1, 2, 3, 4], 
     [5, 6, 1, 2], 
     [3, 4, 5, 6]]) 

你需要做这个或类似的东西:

>>> y = np.zeros((6, 4)) 
>>> y[:x.shape[0], :x.shape[1]] = x 
>>> y 
array([[ 1., 2., 3., 0.], 
     [ 4., 5., 6., 0.], 
     [ 0., 0., 0., 0.], 
     [ 0., 0., 0., 0.], 
     [ 0., 0., 0., 0.], 
     [ 0., 0., 0., 0.]]) 
0

Python字典将作为稀疏阵列很好地工作。主要的问题是初始化稀疏数组的语法会不会很漂亮:

listarray = [100,200,300] 
dictarray = {0:100, 1:200, 2:300} 

但之后的插入或检索元素的语法是一样的

dictarray[5] = 2345 
+0

不幸的是,这不会在n维中工作,并且可能不会像数组那样高效。 – osoucy 2012-07-16 16:20:44