2011-12-05 83 views
9

我无法以python的形式获取我的数据。与namedtuple嵌套

基本上我有一个程序,读取二进制数据,并提供绘图和分析上述数据的功能。

我的数据有主标题和子标题,可以是任何数量不同的数据类型。

我希望能够访问像我的数据,例如:

>>> a = myDatafile.readit() 
>>> a.elements.hydrogen.distributionfunction 
(a big array) 
>>> a.elements.hydrogen.mass 
1 
>>> a.elements.carbon.mass 
12 

,但我不知道原子,直到运行时的名称。

使用namedtuple我已经在所有的原子名称读出之后我尝试过,例如:

self.elements = namedtuple('elements',elementlist) 

哪里元素列表是例如(“氢”,“碳”)的字符串列表。但问题是我不能嵌套使用这些可例如:

for i in range(0,self.nelements): 
    self.elements[i] = namedtuple('details',['ux','uy','uz','mass','distributionfunction']) 

,然后可以通过访问值例如

self.elements.electron.distributionfunction. 

也许我这样做是完全错误的。我对Python非常不熟悉。我知道如果我不想动态地命名变量,这很容易做到。

我希望我已经明确自己想要达到的目标!

+0

能否请你告诉我们的样本数据? – Abhijit

+0

@abhijit 它相当复杂,可以作为二进制数据读入。 化学元素的数量是从文件变量到文件但是每个元件具有: “的名称(字符串) 质量(双精度) 电荷(双精度) 三维速度网格(3 * N *双精度) 相空间网格(n^6 *双精度)' 我有一个读取二进制文件并将其读入变量的类,但是我无法创建可以按照我所描述的方式访问的数据结构。 –

回答

5

不知道您的数据,我们只能给出一个通用的解决方案。

考虑到前两行包含标题和子标题阅读它以某种方式确定了层次结构。你所要做的就是创建一个分层字典。

例如,延长你的榜样

data.elements.hydrogen.distributionfunction 
data.elements.nitrogen.xyzfunction 
data.elements.nitrogen.distributionfunction 
data.compound.water.distributionfunction 
data.compound.hcl.xyzfunction 

因此,我们必须创建一个字典作为这样

{'data':{'elements':{'hydrogen':{'distributionfunction':<something>} 
        'nitrogen':{'xyzfunction':<something>, 
          'distributionfunction':<something>} 
       } 
     compound:{'water':{'distributionfunction':<something>} 
       'hcl':{'xyzfunction':<something>} 
       } 
     } 
} 

字典如何将填充取决于这很难说现在的数据。 但是字典的关键字应该从标题填充,并且不知何故,您必须将数据映射到字典空槽中的相应值。

一旦地图被填充,您可以访问它作为

yourDict['data']['compound']['hcl']['xyzfunction'] 
+0

感谢您的快速响应!那么这将适用于任何数据类型?例如,如果某些字段是字符串,并且某些字段是numpy数组?所以我可以做'分配函数':self.dist1其中self.dist1是一个3d numpy数组? 再次感谢!我非常感谢你的时间! –

+0

正如您在示例中所看到的,我只将有意义的键设置为字符串(可以散列)。只要密钥是可散列的,你就可以在值中存储任何东西,任何数据类型,函数,对象,你想要的东西。 – Abhijit

2

如果你的元素名称是动态的,在运行时所获得的数据,你可以将它们分配到一个字典和访问这样

elements['hydrogen'].mass 

但是如果你想要虚线符号,你可以在运行时创建属性例如

from collections import namedtuple 

class Elements(object): 
    def add_element(self, elementname, element): 
     setattr(self, elementname, element) 

Element = namedtuple('Element', ['ux','uy','uz','mass','distributionfunction']) 

elements = Elements() 
for data in [('hydrogen',1,1,1,1,1), ('helium',2,2,2,2,2), ('carbon',3,3,3,3,3)]: 
    elementname = data[0] 
    element = Element._make(data[1:]) 
    elements.add_element(elementname, element) 

print elements.hydrogen.mass 
print elements.carbon.distributionfunction 

在这里,我假设你有数据,但与其他任何格式的数据,你可以做类似的招数

1

下面是递归创建从嵌套数据namedtuples的方法。

from collections import Mapping, namedtuple 


def namedtuplify(mapping, name='NT'): # thank you https://gist.github.com/hangtwenty/5960435 
    """ Convert mappings to namedtuples recursively. """ 
    if isinstance(mapping, Mapping): 
     for key, value in list(mapping.items()): 
      mapping[key] = namedtuplify(value) 
     return namedtuple_wrapper(name, **mapping) 
    elif isinstance(mapping, list): 
     return [namedtuplify(item) for item in mapping] 
    return mapping 

def namedtuple_wrapper(name, **kwargs): 
    wrap = namedtuple(name, kwargs) 
    return wrap(**kwargs) 


stuff = {'data': {'elements': {'hydrogen': {'distributionfunction': 'foo'}, 
    'nitrogen': {'xyzfunction': 'bar', 
    'distributionfunction': 'baz'} 
    }, 
    'compound': {'water': {'distributionfunction': 'lorem'}, 
    'hcl': {'xyzfunction': 'ipsum'}}} 
} 

example = namedtuplify(stuff) 

example.data.elements.hydrogen.distributionfunction # 'foo' 
+0

这太好了。唯一的问题是它不会与泡菜串连,因为泡菜不能跟踪结构。我做了一个增强版本。我会在下面发帖。 – BobbyG

0

我有嵌套的JSON同样的问题,但要能与连载咸菜不喜欢你动态创建对象的输出需要。

我已经采取了@ bren的答案并对其进行了增强,使得生成的结构将与pickle串行化。你必须保存对你为全局变量创建的每个结构的引用,这样pickle才能保持对它们的标签。

############################################## 
class Json2Struct: 
    ''' 
    Convert mappings to nested namedtuples 

    Usage: 
     jStruct = Json2Struct('JS').json2Struct(json) 
    ''' 
############################################## 

    def __init__(self, name): 
     self.namePrefix = name 
     self.nameSuffix = 0 


    def json2Struct(self, jsonObj): # thank you https://gist.github.com/hangtwenty/5960435 
     """ 
     Convert mappings to namedtuples recursively. 
     """ 
     if isinstance(jsonObj, Mapping): 
      for key, value in list(jsonObj.items()): 
       jsonObj[key] = self.json2Struct(value) 
      return self.namedtuple_wrapper(**jsonObj) 
     elif isinstance(jsonObj, list): 
      return [self.json2Struct(item) for item in jsonObj] 
     return jsonObj 


    def namedtuple_wrapper(self, **kwargs): 
     self.nameSuffix += 1 
     name = self.namePrefix + str(self.nameSuffix) 

     Jstruct = namedtuple(name, kwargs) 
     globals()[name] = Jstruct 

     return Jstruct(**kwargs) 

下面的例子应该如下工作,也可以serialisable:

stuff = {'data': {'elements': {'hydrogen': {'distributionfunction': 'foo'}, 
    'nitrogen': {'xyzfunction': 'bar', 
    'distributionfunction': 'baz'} 
    }, 
    'compound': {'water': {'distributionfunction': 'lorem'}, 
    'hcl': {'xyzfunction': 'ipsum'}}} 
} 

example = Json2Struct('JS').json2Struct(stuff) 

example.data.elements.hydrogen.distributionfunction # 'foo'