YAML सरणियों का विलय कैसे करें?


113

मैं YAML में सरणियों का विलय करना चाहूंगा, और उन्हें माणिक के माध्यम से लोड करूंगा -

some_stuff: &some_stuff
 - a
 - b
 - c

combined_stuff:
  <<: *some_stuff
  - d
  - e
  - f

मैं संयुक्त सरणी के रूप में करना चाहते हैं [a,b,c,d,e,f]

मुझे त्रुटि मिलती है: ब्लॉक मैपिंग पार्स करते समय अपेक्षित कुंजी नहीं मिली

मैं YAML में सरणियों का विलय कैसे करूं?


6
जिस भाषा के साथ आप इसे पार्स कर रहे हैं, उसके बजाय आप इसे YAML में क्यों करना चाहते हैं?
पैट्रिक कॉलिन्स

7
एक बहुत बड़ी yaml फ़ाइल में दोहराव को सुखाने के लिए
lfender6445

4
यह बहुत बुरा अभ्यास है। आपको अलग से yamls पढ़ना चाहिए, रुबी में सरणियों को एक साथ रखना चाहिए, फिर इसे वापस yaml में लिखें।
आरा

74
सूखा बुरा अभ्यास कैसे हो रहा है?
krak3n

13
@PatrickCollins मैंने पाया कि यह प्रश्न मेरे .gitlab-ci.yml फ़ाइल में दोहराव को कम करने की कोशिश कर रहा है और दुर्भाग्य से मुझे उस पार्सर पर कोई नियंत्रण नहीं है जिसका उपयोग GitLab CI करता है :(
rink.attenders.6

जवाबों:


41

यदि उद्देश्य शेल कमांड का एक क्रम चलाना है, तो आप इसे इस प्रकार प्राप्त कर सकते हैं:

# 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

मैं इस पर उपयोग कर रहा हूँ gitlab-ci.yml(जवाब देने के लिए @ rink.attenders.6 सवाल पर टिप्पणी)।


कार्य उदाहरण जो हम requirements.txtgitlab से निजी रिपोज होने का समर्थन करने के लिए उपयोग करते हैं :

.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


3
चतुर। मैं इसे अब हमारी बिटकॉइन पाइपलाइन में उपयोग कर रहा हूं। धन्यवाद
Dariop

* यहां ट्रेलिंग डैश की आवश्यकता नहीं है, केवल अंत में पाइप पर्याप्त है। * यह एक हीन समाधान है जब से नौकरी बहुत लंबी मल्टी-लाइन स्टेटमेंट पर विफल हो जाती है यह स्पष्ट नहीं है कि कौन सी कमांड विफल रही।
मीना ल्यूक

1
@MinaLuke, क्या की तुलना में हीन? वर्तमान में से कोई भी उत्तर केवल यमल का उपयोग करके दो वस्तुओं को मर्ज करने का एक तरीका प्रदान नहीं करता है ... इसके अलावा, इस सवाल में कुछ भी नहीं है कि ओपी सीआई / सीडी में इसका उपयोग करना चाहता है। अंत में, जब यह CI / CD में उपयोग किया जाता है, तो लॉगिंग केवल विशेष CI / CD पर निर्भर करता है, यम घोषणा पर नहीं। इसलिए, अगर कुछ भी, आप जिस सीआई / सीडी का जिक्र कर रहे हैं, वह एक बुरा काम है। इस उत्तर में यम मान्य है, और ओपी की समस्या को हल करता है।
जॉर्ज लेइताओ

@JorgeLeitao मुझे लगता है कि आप इसका उपयोग नियमों को संयोजित करने के लिए करते हैं। क्या आप एक काम करने का उदाहरण प्रदान कर सकते हैं? मैंने आपके समाधान के आधार पर कुछ करने की कोशिश की, लेकिन हमेशा एक सत्यापन त्रुटि मिलती है।
नील्स

@ हनील्स, मैंने एक उदाहरण के साथ काम कर रहे गिट्लाबिसी उदाहरण को जोड़ा है। ध्यान दें कि कुछ IDE इस yaml को अमान्य के रूप में चिह्नित करते हैं, भले ही वह ऐसा न हो।
जॉर्ज लेइताओ

26

अपडेट: 2019-07-01 14:06:12

  • नोट : इस सवाल का एक और जवाब वैकल्पिक दृष्टिकोण पर एक अद्यतन के साथ काफी हद तक संपादित किया गया था ।
    • उस अद्यतन उत्तर में इस उत्तर में वैकल्पिक हल का उल्लेख होता है। इसे नीचे दिए गए See अनुभाग में भी जोड़ा गया है ।

प्रसंग

यह पोस्ट निम्नलिखित संदर्भ मानती है:

  • अजगर 2.7
  • अजगर YAML पार्सर

संकट

lfender6445 एक YAML फ़ाइल के भीतर दो या अधिक सूचियों को मर्ज करना चाहता है, और उन मर्ज किए गए सूचियों को पार्स किए जाने पर एक विलक्षण सूची के रूप में दिखाई देता है।

समाधान (समाधान)

यह केवल मैपिंग के लिए YAML एंकरों को असाइन करके प्राप्त किया जा सकता है, जहां वांछित सूची मैपिंग के बाल तत्वों के रूप में दिखाई देती है। हालांकि, इसके लिए चेतावनी हैं, (देखें "नुकसान" इन्फ्रा)।

नीचे दिए गए उदाहरण में हमारे पास तीन मैपिंग ( list_one, list_two, list_three) और तीन लंगर और उपनाम हैं जो इन मैपिंग का उल्लेख करते हैं जहां उपयुक्त है।

जब YAML फ़ाइल को उस प्रोग्राम में लोड किया जाता है जो हमें वह सूची मिलती है जो हम चाहते हैं, लेकिन लोड के बाद इसे थोड़ा संशोधन की आवश्यकता हो सकती है (देखें गड्ढे निकासी)।

उदाहरण

मूल YAML फ़ाइल

  list_one: & id001
   - ए
   - बी
   - सी

  list_two: और id002
   - इ
   - च
   - जी

  list_three: & id003
   - एच
   - मैं
   - जे

  list_combined:
      - * आइडी001
      - * आईडी 002
      - * आईडी 003

YAML.safe_load के बाद परिणाम

## list_combined
  [
    [
      "ए",
      "बी",
      "सी"
    ],
    [
      "इ",
      'एफ',
      "जी"
    ],
    [
      "H",
      "मैं",
      "जे"
    ]
  ]

नुकसान

  • यह दृष्टिकोण सूचियों की नेस्टेड सूची का उत्पादन करता है, जो सटीक वांछित आउटपुट नहीं हो सकता है, लेकिन यह समतल विधि का उपयोग करके पोस्ट-प्रोसेस किया जा सकता है
  • YAML एंकरों और अन्य नामों पर सामान्य चेतावनियां विशिष्टता और घोषणा आदेश के लिए आवेदन

निष्कर्ष

यह दृष्टिकोण यूलिस के उपनाम और लंगर सुविधा के उपयोग से मर्ज किए गए सूचियों के निर्माण की अनुमति देता है।

हालाँकि आउटपुट परिणाम सूचियों की नेस्टेड सूची है, लेकिन इस flattenपद्धति का उपयोग करके इसे आसानी से रूपांतरित किया जा सकता है ।

यह सभी देखें

@Anthon द्वारा अपडेट किया गया वैकल्पिक तरीका

flattenविधि के उदाहरण


21

यह काम करने वाला नहीं है:

  1. मर्ज केवल मैपिंग के लिए YAML विनिर्देशों द्वारा समर्थित है और अनुक्रमों के लिए नहीं

  2. आप << कुंजी / मान विभाजक :और एक मान के बाद मर्ज की कुंजी के द्वारा पूरी तरह से चीजों को मिला रहे हैं जो एक संदर्भ है और फिर उसी इंडेंटेशन स्तर पर एक सूची के साथ जारी रखें

यह सही नहीं है YAML:

combine_stuff:
  x: 1
  - a
  - b

तो आपके उदाहरण वाक्यविन्यास भी एक YAML विस्तार प्रस्ताव के रूप में मतलब नहीं होगा।

यदि आप कई सरणियों को मर्ज करने जैसा कुछ करना चाहते हैं, तो आप एक वाक्यविन्यास पर विचार करना चाह सकते हैं जैसे:

combined_stuff:
  - <<: *s1, *s2
  - <<: *s3
  - d
  - e
  - f

जहां s1, s2, s3दृश्यों (नहीं दिखाया गया है) कि आप एक नया अनुक्रम में अलग करना चाहते हैं और उसके बाद है पर एंकर हैं d, eऔर f कि के साथ जोड़ दिया। लेकिन YAML पहले इस तरह की संरचनाओं की गहराई का समाधान कर रहा है, इसलिए मर्ज कुंजी के प्रसंस्करण के दौरान कोई वास्तविक संदर्भ उपलब्ध नहीं है। आपके लिए कोई ऐसी सरणी / सूची उपलब्ध नहीं है जहाँ आप संसाधित मान (एंकर अनुक्रम) संलग्न कर सकते हैं।

आप @dreftymac द्वारा प्रस्तावित दृष्टिकोण को अपना सकते हैं, लेकिन इसका बहुत बड़ा नुकसान है कि आपको किसी तरह यह जानने की जरूरत है कि कौन से निहित दृश्यों को समतल करने की आवश्यकता है (यानी लोड किए गए डेटा संरचना के मूल से "पथ" को जनक अनुक्रम तक ले जाएं,) या कि आप पुनरावर्ती लोड किए गए डेटा संरचना को नेस्टेड सरणियों / सूचियों के लिए खोजते हुए चलते हैं और उन सभी को अंधाधुंध रूप से समतल करते हैं।

एक बेहतर समाधान आईएमओ डेटा संरचनाओं को लोड करने के लिए टैग का उपयोग करना होगा जो आपके लिए सपाट हो। यह स्पष्ट रूप से यह बताने के लिए अनुमति देता है कि चपटा होने की क्या आवश्यकता है और क्या नहीं और आपको इस बात पर पूरा नियंत्रण देता है कि क्या यह समतल लोडिंग के दौरान किया गया है, या पहुंच के दौरान किया गया है। कौन सा चुनना है जो समय और भंडारण स्थान में कार्यान्वयन और दक्षता में आसानी का मामला है। यह वही ट्रेड-ऑफ है जिसे मर्ज की प्रमुख विशेषता को लागू करने के लिए किए जाने की आवश्यकता है और ऐसा कोई भी समाधान नहीं है जो हमेशा सबसे अच्छा हो।

उदाहरण के लिए, मेरा ruamel.yamlपुस्तकालय अपने सुरक्षित-लोडर का उपयोग करते समय लोडिंग के दौरान ब्रूट बल मर्ज-डिक्ट्स का उपयोग करता है, जिसके परिणामस्वरूप मर्ज किए गए शब्दकोशों में सामान्य पायथन डाइक होते हैं। यह मर्जिंग अप-फ्रंट किया जाना है, और डेटा (स्पेस अक्षम) को डुप्लिकेट करता है, लेकिन वैल्यू लुकअप में तेज है। राउंड-ट्रिप-लोडर का उपयोग करते समय, आप मर्ज किए गए मर्ज को डंप करने में सक्षम होना चाहते हैं, इसलिए उन्हें अलग रखने की आवश्यकता है। राउंड-ट्रिप-लोडिंग के परिणामस्वरूप लोड किए गए डिएटास्ट्रक्चर जैसा तानाशाह अंतरिक्ष में कुशल है, लेकिन उपयोग में धीमा है, क्योंकि इसे मर्ज में ही नहीं मिल पाने वाली कुंजी को खोजने की कोशिश करने और देखने की जरूरत है (और यह कैश्ड नहीं है, इसलिए यह हर बार किया जाना चाहिए)। बेशक इस तरह के विचार अपेक्षाकृत छोटे कॉन्फ़िगरेशन फ़ाइलों के लिए बहुत महत्वपूर्ण नहीं हैं।


निम्नलिखित वस्तुओं को टैग के साथ वस्तुओं का उपयोग करते हुए अजगर में सूचियों के लिए एक मर्ज की योजना लागू होती है, जो उन वस्तुओं flatten पर पुनरावृत्ति करता है जो सूची और टैग किए गए हैं toflatten। इन दो टैगों का उपयोग करके आपके पास YAML फाइल हो सकती है:

l1: &x1 !toflatten
  - 1 
  - 2
l2: &x2
  - 3 
  - 4
m1: !flatten
  - *x1
  - *x2
  - [5, 6]
  - !toflatten [7, 8]

(प्रवाह बनाम ब्लॉक शैली अनुक्रमों का उपयोग पूरी तरह से मनमाना है और लोड किए गए परिणाम पर कोई प्रभाव नहीं है)।

जब उन वस्तुओं के बारे में पुनरावृति होती है जो कुंजी के लिए मूल्य हैं, तो m1यह "अनुक्रम" में अनुक्रम के साथ टैग किया जाता है toflatten, लेकिन एकल सूची के रूप में अन्य सूचियों (उपनाम या नहीं) को प्रदर्शित करता है।

इसे प्राप्त करने के लिए पायथन कोड के साथ एक संभव तरीका:

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

, अर्थात् एक लंगर अनुक्रम को टैग करें, क्योंकि यह अनिवार्य रूप से इसे एक अलग डेटास्ट्रक्चर में बना देगा।

स्पष्ट टैग का उपयोग करना IMO से अच्छा है क्योंकि कुछ मैजिक, जैसे कि YAML मर्ज कीज़ के साथ चल रहा है <<। यदि आपके पास अब कुछ नहीं है तो आपको हुप्स के माध्यम से जाना होगा यदि आपके पास एक मैपिंग के साथ एक YAML फ़ाइल होती है जिसमें एक कुंजी होती है <<जिसे आप मर्ज की तरह कार्य नहीं करना चाहते हैं, उदाहरण के लिए जब आप सी ऑपरेटरों के मानचित्रण को उनके विवरण के लिए बनाते हैं अंग्रेजी में (या कुछ अन्य प्राकृतिक भाषा)।


9

यदि आपको केवल एक आइटम को एक सूची में मर्ज करने की आवश्यकता है जो आप कर सकते हैं

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

-4

आप मैपिंग को मर्ज कर सकते हैं और फिर इन शर्तों के तहत उनकी कुंजियों को सूची में बदल सकते हैं:

  • यदि आप jinja2 templating और का उपयोग कर रहे हैं
  • यदि आइटम ऑर्डर महत्वपूर्ण नहीं है
some_stuff: &some_stuff
 a:
 b:
 c:

combined_stuff:
  <<: *some_stuff
  d:
  e:
  f:

{{ combined_stuff | list }}

इस उत्तर में क्या गलत है? अगर वे तर्क-वितर्क करते हैं तो मुझे बुरा नहीं लगता। मैं उन लोगों के लिए जवाब रखूंगा जो इसका उपयोग कर सकते हैं।
sm4rk0

3
शायद इसलिए क्योंकि यह जवाब jinja2 टेम्प्लेटिंग पर निर्भर करता है, जब प्रश्न yml में इसे करने के लिए कहता है। jinja2 को पाइथन पर्यावरण की आवश्यकता होती है, जो कि ओपी DRY के लिए प्रयास कर रहा है तो प्रति-उत्पादक है। इसके अलावा, कई CI / CD उपकरण एक अस्थायी कदम को स्वीकार नहीं करते हैं।
जॉर्ज लेइताओ

धन्यवाद @JorgeLeitao यह समझ आता है। मैं एक साथ खेलने योग्य पुस्तकों और टेम्पलेट्स को विकसित करते हुए YAML और Jinja2 को एक साथ सीखता हूं और एक के बिना एक के बारे में नहीं सोच सकता
sm4rk0
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.