YAML 어레이를 Marge하는 방법
YAML에서 어레이를 Marge하여 Ruby로 로드하고 싶습니다.
some_stuff: &some_stuff
- a
- b
- c
combined_stuff:
<<: *some_stuff
- d
- e
- f
은 합된음음음음음음음음음음음음음 as as as as as as as 로 해 주세요[a,b,c,d,e,f]
오류 발생: 블록 매핑을 구문 분석하는 동안 예상된 키를 찾을 수 없습니다.
YAML에서 어레이를 Marge하려면 어떻게 해야 합니까?
일련의 셸 명령어를 실행하는 것이 목적이라면 다음과 같이 실행할 수 있습니다.
# note: no dash before commands
some_stuff: &some_stuff |-
a
b
c
combined_stuff:
- *some_stuff
- d
- e
- f
이는 다음과 같습니다.
some_stuff: "a\nb\nc"
combined_stuff:
- "a\nb\nc"
- d
- e
- f
는 이것을 의 가걸 my my 하고 있다.gitlab-ci.yml
(answer@rink.at에서 확인).
「 」를 서포트하기 위해서 사용하는 예requirements.txt
gitlab의 개인 저장소가 있습니다.
.pip_git: &pip_git
- git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com".insteadOf "ssh://git@gitlab.com"
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
test:
image: python:3.7.3
stage: test
script:
- *pip_git
- pip install -q -r requirements_test.txt
- python -m unittest discover tests
use the same `*pip_git` on e.g. build image...
서 ''는requirements_test.txt
아, 아, 아, 아, 아, 아, 아, 아, 아, 아.
-e git+ssh://git@gitlab.com/example/example.git@v0.2.2#egg=example
이 조작은 동작하지 않습니다.
Merge는 매핑의 YAML 사양에서만 지원되며 시퀀스에서는 지원되지 않습니다.
수 있는 입니다.
<<
구분자 "/값 구분자"가 지정됩니다.:
참조가 되고 동일한 들여쓰기 수준에서 목록을 계속하는 값입니다.
이것은 올바른 YAML이 아닙니다.
combine_stuff:
x: 1
- a
- b
따라서 이 예제 구문은 YAML 확장 제안서로서도 의미가 없습니다.
여러 어레이를 병합하는 등의 작업을 수행할 경우 다음과 같은 구문을 고려할 수 있습니다.
combined_stuff:
- <<: *s1, *s2
- <<: *s3
- d
- e
- f
서 ''는s1
,s2
,s3
하고 되어 있지 않음)의이며, 그 후 (「」 「」 「Marge」 「」, 「」 「Marge」, 「」, 「」, 「」를 가지고 있습니다.d
,e
★★★★★★★★★★★★★★★★★」f
거기에 덧붙입니다.그러나 YAML은 이러한 구조의 깊이를 먼저 해결하고 있기 때문에 Marge Key 처리 중에는 실제 컨텍스트를 사용할 수 없습니다.처리한 값(고정 시퀀스)을 부가할 수 있는 어레이/리스트가 없습니다.
@dreftymac의 제안대로 어프로치를 취할 수 있지만, 이것은 어떤 중첩된 시퀀스를 평탄하게 할 필요가 있다는 큰 단점이 있습니다(로드된 데이터 구조의 루트에서 부모 시퀀스로의 「패스」를 아는 것).또는 로드된 데이터 구조를 반복적으로 이동하여 중첩된 배열/목록을 검색하고 모든 목록을 무차별적으로 평탄화시킵니다.
IMO는 태그를 사용하여 평탄화하는 데이터 구조를 로드하는 것이 좋습니다.이를 통해 평탄화해야 할 것과 그렇지 않은 것을 명확하게 나타낼 수 있으며, 평탄화가 로드 중에 수행되는지 또는 접근 중에 수행되는지 여부를 완전히 제어할 수 있습니다.어느 쪽을 선택할지는 구현의 용이성과 시간과 스토리지 공간의 효율성의 문제입니다.이는 머지 키 기능의 실장에 필요한 것과 같은 트레이드오프이며, 항상 최적인 솔루션은 없습니다.
my :: 제ruamel.yaml
브루트 포스 머지Python dicts 라 、 Maggedictes 、 Python dicts 。이 병합은 사전에 수행해야 하며 데이터를 복제(공간 비효율적)하지만 값 검색 속도가 빠릅니다.라운드 트립 로더를 사용하는 경우 Marge를 Marge하지 않고 덤프할 수 있으므로 Marge를 개별적으로 유지해야 합니다.라운드 트립 로딩의 결과로 로드된 dict와 같은 데이터 구조는 공간 효율이 높지만 marge에서 dict 자체에서 찾을 수 없는 키를 검색해야 하기 때문에 액세스 속도가 느립니다(그리고 이것은 캐시되지 않으므로 매번 수행해야 합니다).물론 비교적 작은 구성 파일에는 이러한 고려 사항이 그다지 중요하지 않습니다.
가 붙은 에 대해 합니다.flatten
및가 붙은 하는 온 더 플라이toflatten
이하여 YAML 수 다음 2개의 태그를 사용하여 YAML 파일을 얻을 수 있습니다.
l1: &x1 !toflatten
- 1
- 2
l2: &x2
- 3
- 4
m1: !flatten
- *x1
- *x2
- [5, 6]
- !toflatten [7, 8]
(플로우 vs 블록 스타일 시퀀스의 사용은 완전히 임의이며 로드된 결과에 영향을 미치지 않습니다.)
할 때m1
해서 '', '이러다', '이러다', '이러다', '이러다', '이러다', '이러다', '이러다', '이러다', '이러다', '이러다', '이러다 거예요.toflatten
단, 다른 목록(에일리어스 여부)을 단일 항목으로 표시합니다.
Python 코드로 이를 달성할 수 있는 방법 중 하나는 다음과 같습니다.
import sys
from pathlib import Path
import ruamel.yaml
yaml = ruamel.yaml.YAML()
@yaml.register_class
class Flatten(list):
yaml_tag = u'!flatten'
def __init__(self, *args):
self.items = args
@classmethod
def from_yaml(cls, constructor, node):
x = cls(*constructor.construct_sequence(node, deep=True))
return x
def __iter__(self):
for item in self.items:
if isinstance(item, ToFlatten):
for nested_item in item:
yield nested_item
else:
yield item
@yaml.register_class
class ToFlatten(list):
yaml_tag = u'!toflatten'
@classmethod
def from_yaml(cls, constructor, node):
x = cls(constructor.construct_sequence(node, deep=True))
return x
data = yaml.load(Path('input.yaml'))
for item in data['m1']:
print(item)
출력:
1
2
[3, 4]
[5, 6]
7
8
보시다시피 평탄화가 필요한 시퀀스에서는 태그가 달린 시퀀스의 에일리어스를 사용하거나 태그가 달린 시퀀스를 사용할 수 있습니다.YAML에서는 다음 작업을 수행할 수 없습니다.
- !flatten *x2
즉, 고정 시퀀스에 태그를 붙이면 본질적으로 다른 데이터 구조가 되기 때문입니다.
YAML 머지 키와 같은 마법이 진행되는 것보다 명시적인 태그를 사용하는 것이 IMO에 더 좋습니다.<<
이 있는 YAML , 그 는, 를 실시할 필요가 <<
예를 들어 C 연산자를 영어(또는 기타 자연어)로 설명에 매핑할 때 병합 키 역할을 하지 않는 것이 좋습니다.
갱신일 : 2019-07-01 14:06:12
- 참고: 이 질문에 대한 또 다른 답변은 대체 접근법에 대한 업데이트를 통해 대폭 수정되었습니다.
- 이 갱신된 답변에서는 이 답변의 회피책의 대안이 제시되어 있습니다.아래의 '또한 참조' 섹션에 추가되어 있습니다.
맥락
이 투고에서는, 다음의 콘텍스트를 상정하고 있습니다.
- python 2.7
- python YAML 파서
문제
lfender6445는 YAML 파일 내의 여러 목록을 Marge하고 이러한 Marge된 목록을 해석할 때 하나의 단일 목록으로 표시하려고 합니다.
솔루션 (회피책)
이것은 YAML 앵커를 매핑에 할당하는 것만으로 얻을 수 있습니다.이 매핑에서는 원하는 리스트가 매핑의 하위 요소로 표시됩니다.그러나 여기에는 경고 사항이 있습니다("함정" 인프라 참조).
의 매핑하다, 3개의 매핑)이 .list_one, list_two, list_three
3개의 앵커와 에일리어스(해당하는 경우 이들 매핑을 참조).
프로그램에 YAML 파일이 로드되면 원하는 목록을 얻을 수 있지만 로드 후 약간의 수정이 필요할 수 있습니다(아래 함정 참조).
예
원본 YAML 파일
list_1: &id001- a- b(c) list_2: &id002(e)(f)(g) list_3: &id003- h- i(j). list_filename: (*id001).(*id002).(*id003).
YAML.safe_load 후 결과
## 리스트_개요[["a","b","c"],["e","f","g"],["h",'나',"j"]]
함정
- 이 접근방식은 리스트의 네스트 리스트를 생성합니다.이 리스트는 원하는 정확한 출력은 아닐 수 있지만, 이것은 평탄한 방법을 사용하여 포스트 리셋할 수 있습니다.
- YAML 앵커 및 에일리어스에 대한 일반적인 경고는 고유성 및 선언 순서에 적용됩니다.
결론
이 방법을 사용하면 YAML의 에일리어스 및 앵커 기능을 사용하여 Marge 목록을 작성할 수 있습니다.
이지만, 은 「」, 「」를 해 간단하게 할 수 .flatten
★★★★★★ 。
「 」를 참조해 주세요.
@Anthon에 의한 대체 접근법 갱신
의 예flatten
flatten
;; 어레이의 Marge/flatening을 실시합니다.- ★★★
flatten
;; http://ruby-doc.org/core-2.2.2/Array.html#method-i-flatten - Python 이 python
flatten
;; https://softwareengineering.stackexchange.com/a/254676/23884
하나의 항목만 목록에 병합해야 하는 경우 다음을 수행할 수 있습니다.
fruit:
- &banana
name: banana
colour: yellow
food:
- *banana
- name: carrot
colour: orange
그 결과
fruit:
- name: banana
colour: yellow
food:
- name: banana
colour: yellow
- name: carrot
colour: orange
또 다른 은 python을 입니다.!flatten
PyYAML을 사용하다수 백엔드에서 사용되는 패키지)에합니다.anyconfig
를 참조해 주세요.
import yaml
yaml.add_constructor("!flatten", construct_flat_list)
def flatten_sequence(sequence: yaml.Node) -> Iterator[str]:
"""Flatten a nested sequence to a list of strings
A nested structure is always a SequenceNode
"""
if isinstance(sequence, yaml.ScalarNode):
yield sequence.value
return
if not isinstance(sequence, yaml.SequenceNode):
raise TypeError(f"'!flatten' can only flatten sequence nodes, not {sequence}")
for el in sequence.value:
if isinstance(el, yaml.SequenceNode):
yield from flatten_sequence(el)
elif isinstance(el, yaml.ScalarNode):
yield el.value
else:
raise TypeError(f"'!flatten' can only take scalar nodes, not {el}")
def construct_flat_list(loader: yaml.Loader, node: yaml.Node) -> List[str]:
"""Make a flat list, should be used with '!flatten'
Args:
loader: Unused, but necessary to pass to `yaml.add_constructor`
node: The passed node to flatten
"""
return list(flatten_sequence(node))
문서 을 PyYAML로 합니다.SequenceNode
및 을 ""로 지정합니다.ScalarNode
은 다음 기능에서 수정 수 있습니다. 동작은 다음 테스트 기능으로 테스트(및 수정)할 수 있습니다.
import pytest
def test_flatten_yaml():
# single nest
param_string = """
bread: &bread
- toast
- loafs
chicken: &chicken
- *bread
midnight_meal: !flatten
- *chicken
- *bread
"""
params = yaml.load(param_string)
assert sorted(params["midnight_meal"]) == sorted(
["toast", "loafs", "toast", "loafs"]
)
다음과 같은 경우 매핑을 병합한 후 해당 키를 목록으로 변환할 수 있습니다.
- jinja2 템플리트를 사용하고 있다면
- 아이템 순서가 중요하지 않은 경우
some_stuff: &some_stuff
a:
b:
c:
combined_stuff:
<<: *some_stuff
d:
e:
f:
{{ combined_stuff | list }}
언급URL : https://stackoverflow.com/questions/24090177/how-to-merge-yaml-arrays
'programing' 카테고리의 다른 글
SQL Server에서 Cascading을 사용해야 하는 이유 및 시기 (0) | 2023.04.10 |
---|---|
이전 bash 명령어 인수를 호출하려면 어떻게 해야 합니까? (0) | 2023.04.10 |
C++ 문자열에서 발생한 문자 수 (0) | 2023.04.10 |
로컬 변경을 무시한 채 git pull을 하려면 어떻게 해야 합니까? (0) | 2023.04.10 |
UIView의 고정 높이 구속조건을 프로그래밍 방식으로 업데이트하려면 어떻게 해야 합니까? (0) | 2023.04.10 |