2012-07-13 91 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