สิ่งนี้จะไม่ทำงาน:
การผสานได้รับการสนับสนุนโดยข้อกำหนด YAML สำหรับการแมปเท่านั้นไม่ใช่สำหรับลำดับ
คุณกำลังผสมสิ่งต่าง ๆ อย่างสมบูรณ์โดยมีคีย์ผสาน<<
ตามด้วยตัวคั่นคีย์ / ค่า:
และค่าที่เป็นข้อมูลอ้างอิงจากนั้นดำเนินการต่อด้วยรายการที่ระดับการเยื้องเดียวกัน
นี่ไม่ใช่ YAML ที่ถูกต้อง:
combine_stuff:
x: 1
- a
- b
ดังนั้นไวยากรณ์ตัวอย่างของคุณจึงไม่สมเหตุสมผลกับข้อเสนอส่วนขยาย YAML
หากคุณต้องการดำเนินการบางอย่างเช่นการรวมอาร์เรย์หลายรายการคุณอาจต้องการพิจารณาไวยากรณ์เช่น:
combined_stuff:
- <<: *s1, *s2
- <<: *s3
- d
- e
- f
ที่s1
, s2
, s3
มีเบรกลำดับ (ไม่แสดง) ที่คุณต้องการที่จะรวมกันเป็นลำดับใหม่แล้วมีd
, e
และf
ต่อท้ายว่า แต่ YAML กำลังแก้ไขความลึกของโครงสร้างประเภทนี้ก่อนดังนั้นจึงไม่มีบริบทที่แท้จริงในระหว่างการประมวลผลคีย์การผสาน ไม่มีอาร์เรย์ / รายการสำหรับคุณที่คุณสามารถแนบค่าที่ประมวลผลแล้ว (ลำดับที่ยึด) กับ
คุณสามารถใช้แนวทางตามที่เสนอโดย @dreftymac แต่สิ่งนี้มีข้อเสียอย่างมากที่คุณจำเป็นต้องรู้ว่าลำดับที่ซ้อนกันใดที่จะทำให้แบน (กล่าวคือโดยการรู้ "เส้นทาง" จากรากของโครงสร้างข้อมูลที่โหลดไปยังลำดับพาเรนต์) หรือว่าคุณเดินตามโครงสร้างข้อมูลที่โหลดซ้ำเพื่อค้นหาอาร์เรย์ / รายการที่ซ้อนกันและทำให้แบนราบทั้งหมด
ทางออกที่ดีกว่า IMO คือการใช้แท็กเพื่อโหลดโครงสร้างข้อมูลที่ทำให้แบนสำหรับคุณ สิ่งนี้ช่วยให้สามารถระบุได้อย่างชัดเจนว่าต้องแบนอะไรและอะไรไม่ได้และช่วยให้คุณควบคุมได้อย่างเต็มที่ว่าการแบนนี้จะเกิดขึ้นระหว่างการโหลดหรือทำในระหว่างการเข้าถึง สิ่งที่ต้องเลือกคือเรื่องของการใช้งานที่ง่ายและมีประสิทธิภาพในเวลาและพื้นที่จัดเก็บ นี่เป็นการแลกเปลี่ยนแบบเดียวกับที่ต้องทำเพื่อใช้คุณลักษณะคีย์การผสานและไม่มีโซลูชันเดียวที่ดีที่สุดเสมอไป
เช่นruamel.yaml
ไลบรารีของฉันใช้ brute force merge-dict ในระหว่างการโหลดเมื่อใช้ safe-loader ซึ่งส่งผลให้พจนานุกรมรวมที่เป็น Python ตามปกติ การรวมนี้จะต้องดำเนินการล่วงหน้าและข้อมูลที่ซ้ำกัน (พื้นที่ไม่มีประสิทธิภาพ) แต่สามารถค้นหาค่าได้อย่างรวดเร็ว เมื่อใช้ตัวโหลดแบบไปกลับคุณต้องการที่จะสามารถถ่ายโอนข้อมูลการผสานที่ไม่ได้ผสานดังนั้นจึงต้องแยกกัน คำสั่งเช่นโครงสร้างข้อมูลที่โหลดอันเป็นผลมาจากการโหลดแบบไปกลับเป็นพื้นที่ที่มีประสิทธิภาพ แต่เข้าถึงได้ช้าลงเนื่องจากต้องลองและค้นหาคีย์ที่ไม่พบในตัวเองในการผสาน (และสิ่งนี้ไม่ได้ถูกแคชไว้ดังนั้น ต้องทำทุกครั้ง) แน่นอนว่าการพิจารณาดังกล่าวไม่สำคัญมากสำหรับไฟล์คอนฟิกูเรชันที่ค่อนข้างเล็ก
ต่อไปนี้การดำเนินการผสานเช่นโครงการสำหรับรายการในหลามใช้วัตถุที่มีแท็กflatten
ซึ่ง on-the-fly การ recurses toflatten
เข้าไปในรายการซึ่งเป็นรายการและติดแท็ก การใช้สองแท็กนี้คุณสามารถมีไฟล์ 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
กล่าวคือแท็กลำดับที่ยึดไว้เนื่องจากจะทำให้เป็นโครงสร้างข้อมูลที่แตกต่างกัน
การใช้อย่างชัดเจนแท็ก IMO <<
ดีกว่ามีความมหัศจรรย์บางอย่างที่เกิดขึ้นเช่นเดียวกับปุ่มผสาน หากไม่มีสิ่งอื่นใดตอนนี้คุณต้องผ่านห่วงหากคุณมีไฟล์ YAML ที่มีการแมปที่มีคีย์
<<
ที่คุณไม่ต้องการทำหน้าที่เหมือนคีย์ผสานเช่นเมื่อคุณทำการแมปตัวดำเนินการ C กับคำอธิบาย เป็นภาษาอังกฤษ (หรือภาษาธรรมชาติอื่น ๆ )