【问题标题】:Creating arrays in Python without pre-populating with data在 Python 中创建数组而不预先填充数据
【发布时间】:2011-09-17 04:49:26
【问题描述】:

enter code here有没有一种方法可以在 Python 中创建(多维)数组,而无需用数据预先填充这些数组?

具体来说,我正在寻找与我找到的 Ironpython 解决方案 here 等效的东西:

import clr

from System import Array,Boolean,Double

from System.Activator import CreateInstance

a=clr.Reference[Array[str]](Array[str](('')))

b=clr.Reference[Array[float]](Array.CreateInstance(Double,0))

我尝试使用 ctypes(例如 a=(c_double*2*3)() ),但是这样数组就预先填充了零。 有什么想法吗?

问题是我有一个带有 API 的 COM 对象,其功能类似于:

ret=function(var1,var2,var3,...)

其中 var1,var2,var3 是由值填充的多维数组。 如果我使用 Ironpython,我可以通过 System 模块与 COM 对象进行通信,例如:

from System.Type import GetTypeFromProgID
from System.Activator import CreateInstance

# Create Sap2000 object
sap = CreateInstance(GetTypeFromProgID("Sap2000.SapObject"))

然后我通过使用 clr.Reference 构建 var1、var2、var3 来解决我的问题...

在 CPython 中,我使用 win32com.client 模块与 COM 对象进行通信,但现在我不知道如何构建 var1、var2、var3 以便它们在函数中工作。

谢谢,

代码如下:

import win32com.client 
from ctypes import*


def Sap2000():
    sap,SapModel=OpenSap2000(Visible = True)
    NewModel(SapModel)

    #define material property
    ret = SapModel.PropMaterial.SetMaterial("CONC", 2) #MATERIAL_CONCRETE)

    #assign isotropic mechanical properties to material
    ret = SapModel.PropMaterial.SetMPIsotropic("CONC", 3600, 0.2, 0.0000055)

    #create model from template
    ret = SapModel.File.New2DFrame(0, 3, 124, 3, 200) # 0=PortalFrame

    #run analysis
    ret = SapModel.File.Save("C:\SapAPI\xy.sdb")
    ret = SapModel.Analyze.RunAnalysis

    #clear all case and combo output selections
    ret = SapModel.Results.Setup.DeselectAllCasesAndCombosForOutput

    #set case and combo output selections
    ret = SapModel.Results.Setup.SetCaseSelectedForOutput("DEAD")

    #get point displacements

    # Arrays passed by ref
    #Obj=clr.Reference[Array[str]](Array[str](('')))
    Obj=[[""]]
    #Elm=clr.Reference[Array[str]](Array[str](('')))
    Elm=[[""]]
    #LoadCase=clr.Reference[Array[str]](Array[str](('')))
    LoadCase=[[""]]
    #StepType=clr.Reference[Array[str]](Array[str](('')))
    StepType=[[""]]

    #StepNum=clr.Reference[Array[float]](Array.CreateInstance(Double,0))
    StepNum=(c_double*3*2)()
    #U1=clr.Reference[Array[float]](Array.CreateInstance(Double,0))
    U1=(c_double*3*2)()
    #U2=clr.Reference[Array[float]](Array.CreateInstance(Double,0))
    U2=(c_double*3*2)()
    #U3=clr.Reference[Array[float]](Array.CreateInstance(Double,0))
    U3=(c_double*3*2)()
    #R1=clr.Reference[Array[float]](Array.CreateInstance(Double,0))
    R1=(c_double*3*2)()
    #R2=clr.Reference[Array[float]](Array.CreateInstance(Double,0))
    R2=(c_double*3*2)()
    #R3=clr.Reference[Array[float]](Array.CreateInstance(Double,0))
    R3=(c_double*3*2)()
    ret = SapModel.Results.JointDispl("ALL", GroupElm, NumberResults, Obj, Elm, LoadCase, StepType, StepNum, U1, U2, U3, R1, R2, R3)
    print ret




def OpenSap2000(Units='kN_m_C',Visible = False,FileName=''):
    # Create Sap2000 object
    sap = win32com.client.Dispatch("Sap2000.SapObject")

    # Start application
    ret=sap.ApplicationStart(6,Visible,FileName)
    print ret
    SapModel=sap.SapModel

    return sap,SapModel


def NewModel(SapModel,Units='kN_m_C'):
    # Initialize new model
    #SapModel=sap.SapModel
    u=SetUnits(Units)
    ret = SapModel.InitializeNewModel(u)
    # New blank model
    ret = SapModel.File.NewBlank()
    return


if __name__=="__main__":
    Sap2000()

调用 SapModel.Results.JointDispl(..) 函数失败。

ApplyTypes 中的文件“C:\Python26\Lib\site-packages\win32com\client__init__.py”,第 456 行 self.oleobj.InvokeTypes(dispid, 0, wFlags, retType, argTypes, *args), TypeError: SAFEARRAYS 的对象必须是(序列的)序列或缓冲区对象。

【问题讨论】:

  • 为什么那里必须没有数据?是因为你认为这样更快吗?
  • 我在第一篇文章中添加了一些关于我试图面对的问题的规范。 @Cosmologicon:性能不是问题@lazyr:我在看你的链接
  • 你为什么不向我们展示使用 win32com.client 的代码,直到它不起作用为止。对于下面的所有猜测,没有人能理解您的问题。

标签: python multidimensional-array


【解决方案1】:

应该预先填充什么?你的用例是什么?

我认为对维度数组 (x, y) 最快的解决方案是:

a = [[None] * x for i in range(y)]

这将为您提供一个带有None 值的多维数组,表示您尚未设置任何值的位置。

【讨论】:

  • a 内部,您有三次相同的列表,因此,例如,当您更改a[1][1] 时,您将同时更改a[0][1]a[0][2]。跨度>
  • 我应该指定一个类型,而不是维度或值。假设我想要一个双精度或字符串的多维数组(2 层)(如我发布的 Ironpython 示例)。
  • 你们都错了:Daren:它需要以“for i in range(y)”结尾,而Dave,这是避免共享列表问题的正确方法。
  • @Ned - 自从我添加评论后,Daren 编辑了他的答案。原来是[[None] * x] * y
  • 分配无值并不能解决我的问题。就像我需要在 python 中声明一个变量......也许使用 Cython??
【解决方案2】:

list 条目有一些价值,但您可以使用 None

对于一维“数组”,它很简单:

[None] * 3

对于二维数组,您必须更加小心,因为您不希望所有嵌套列表都位于同一个列表中,因此您可以执行以下操作:

[[None] * 2 for _ in range(3)]

另一种选择是使用带有元组的dict 作为键,但这也没有固定的大小。

>>> d = {}
>>> d[(1,1)] = 2
>>> d[(1,1)]
2
>>> d[(1,2)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: (1, 2)

array module 提供类型化的数值数组,但它们与list 类似,因为它们没有固定大小。但是,这些确实需要填充一个值。

>>> from array import array
>>> a = [array('f',[0] * 2) for _ in range(3)]
>>> a
[array('f', [0.0, 0.0]), array('f', [0.0, 0.0]), array('f', [0.0, 0.0])]
>>> a[1][1] = 3.4
>>> a[1][1] = 'string'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: a float is required

【讨论】:

    【解决方案3】:

    如果您不介意使用 NumPy,可以使用 numpy.empty()。 NumPy 可能是多维数组的最佳可用实现。

    【讨论】:

    • 它不能解决问题,因为 numpy.empty(n) 返回一个像 --> array([ 1.25350215e-163, 9.98394023e-317, 1.58456325e+029], . ..)
    • @Paolo,数组必须包含 something。所以 unpopulated 没有任何意义。你的意思是未初始化?如果不必填充已知值,则数组创建速度更快,numpy.empty() 是未初始化的数组。
    • 请看我一开始链接的 Ironpython 话题。我只是使用了我在那里找到的相同的词。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 2013-03-08
    • 1970-01-01
    • 2012-05-10
    • 2021-06-30
    • 1970-01-01
    相关资源
    最近更新 更多