Извлекать объемные данные из YAML, используя Python - PullRequest
0 голосов
/ 06 мая 2018

У меня есть файл yaml в форме ниже:

Solution: 
- number of solutions: 1
  number of solutions displayed: 1
- Gap: None
  Status: optimal
  Message: bonmin\x3a Optimal
  Objective:
    objective:
      Value: 0.010981105395
  Variable:
    battery_E[b1,1,1]:
      Value: 0.25
    battery_E[b1,1,2]:
      Value: 0.259912707017
    battery_E[b1,2,1]:
      Value: 0.120758408109
    battery_E[b2,1,1]:
      Value: 0.0899999972181
    battery_E[b2,2,3]:
      Value: 0.198967393893
    windfarm_L[w1,2,3]:
      Value: 1
    windfarm_L[w1,3,1]:
      Value: 1
    windfarm_L[w1,3,2]:
      Value: 1

Используя Python27, я хотел бы импортировать все значения battery_E из этого файла YAML. Я знаю, что могу перебирать ключи словаря battery_E, чтобы получать их один за другим (я уже делаю это с помощью PyYAML), но я бы хотел избежать перебора и сделать это за один раз!

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

Это невозможно "за один раз" - в любом случае все равно будет какая-то итерация, и это вполне нормально.

Однако, если память является проблемой, вы можете загрузить только значения ключей, представляющих интерес во время загрузки YAML:

from __future__ import print_function

import yaml

KEY = 'battery_E'


class Loader(yaml.SafeLoader):
    def __init__(self, stream):
        super(Loader, self).__init__(stream)
        self.values = []

    def compose_mapping_node(self, anchor):
        start_event = self.get_event()
        tag = start_event.tag
        if tag is None or tag == '!':
            tag = self.resolve(yaml.MappingNode, None, start_event.implicit)
        node = yaml.MappingNode(tag, [],
                                start_event.start_mark, None,
                                flow_style=start_event.flow_style)
        if anchor is not None:
            self.anchors[anchor] = node
        while not self.check_event(yaml.MappingEndEvent):
            item_key = self.compose_node(node, None)
            item_value = self.compose_node(node, item_key)
            if (isinstance(item_key, yaml.ScalarNode)
                    and item_key.value.startswith(KEY)
                    and item_key.value[len(KEY)] == '['):
                self.values.append(self.construct_object(item_value, deep=True))
            else:
                node.value.append((item_key, item_value))
        end_event = self.get_event()
        node.end_mark = end_event.end_mark
        return node


with open('test.yaml') as f:
    loader = Loader(f)
    try:
        loader.get_single_data()
    finally:
        loader.dispose()

    print(loader.values)

Обратите внимание, что в этом коде ничего не говорится о положении battery_E ключей в дереве внутри файла YAML - он просто загрузит все их значения.

0 голосов
/ 06 мая 2018

Нет необходимости извлекать каждую запись, используя PyYAML, вы можете загрузить данные один раз, а затем использовать Pythons для выбора пар ключ-значение со следующими двумя строками:

data = yaml.safe_load(open('input.yaml'))
kv = {k:v['Value']  for k, v in data['Solution'][1]['Variable'].items() if k.startswith('battery_E')}

после этого kv содержит:

{'battery_E[b2,2,3]': 0.198967393893, 'battery_E[b1,1,1]': 0.25, 'battery_E[b1,1,2]': 0.259912707017, 'battery_E[b2,1,1]': 0.0899999972181, 'battery_E[b1,2,1]': 0.120758408109}
...