Numbered list as YAML array
Asked Answered
F

2

6

Instead of

key:
    - thisvalue
    - thatvalue
    - anothervalue

I would like to have

key:
    1. thisvalue
    2. thatvalue
    3. anothervalue

purely for human readability, with the same interpretation of {key: [thisvalue, thatvalue, anothervalue]}.

This doesn't seem to be part of the basic YAML syntax, but is there a way to achieve this - perhaps using some of the advanced arcanery that's possible in YAML?

(I realize that this can be approximated by writing the list as:

key:
    - 1. thisvalue
    - 2. thatvalue
    - 3. anothervalue

but this is an ugly hack and I'd prefer a solution where the numbers had semantic purpose, rather than being just part of the value's text, that also requires being parsed and removed.)

Flaming answered 2/8, 2015 at 18:38 Comment(1)
Please see the update of my post (the IMPORTANT section at the end).Wynn
W
5

There is no way to do that in YAML. You can however use a normal nesting of elements and then during parsing generate an array/list/dictionary based on those:

my_numbered_pseudo_list:
  1: a
  2: b
  3: c
  ...
  n: x

When you load the example from above you will get the dictionary with key "my_numbered_pseudo_list" and its value as a dictionary containing all nested pairs {"1" : "a", "2" : "b", ..., "n" : "x"}. Here is an example how it will look like:

import yaml

doc = '''
list:
  1: a
  2: b
  3: c
  4: d
'''

y = yaml.load(doc);
list = []

for i in y['list']:
    list.append(y['list'].get(i))

print list

This will give you

['a', 'b', 'c', 'd']

If you want to make sure that the order is actually kept in the YAML file you have to do some sorting in order to get an ordered final list where the order described in the YAML file is kept.

I have also seen people use ordered hash calls on the resulting dictionary (here: "list") (such as in Ruby which I am not familiar with) so you might want to dig a little bit more.

IMPORTANT!

Read here and here. In short to make sure you get a really ordered list from your YAML you have to sort the dictionary you have as a pseudo-list by key and then extract the values and append those to your final list.

Wynn answered 2/8, 2015 at 19:18 Comment(3)
That's brilliant! Thanks. I was about to add to the question that the precise formatting of the numbers didn't matter to me, but I didn't mentally connect that with turning the numbers into keys in a map. Ruby does seem to have reading hashes in order, and was already the language of choice to parse this, but even in other languages a numeric sort on the keys will take care of the ordering, so this is a quite feasible solution to my usecase.Flaming
Cool, glad this helped. :)Wynn
@sundar btw I am pretty sure this is inefficient during the parsing process especially for large lists since you are basically creating a separate dictionary per entry instead of just appending an item to a list. Have this in mind if you want to work with huge data sets.Wynn
F
2

When using Python, in order to be able to preserve the key order in YAML mappings (and comments, anchor names etc), the mappings are read into special ordereddict derivatives if you use ruamel.yaml (diclaimer: I am the author) and the RoundTripLoader.

Those function as dicts transparently, but with that, and using the syntax proposed by rbaleksandar in her/his answer, you can just do:

import ruamel.yaml as yaml

yaml_str = """\
key:
    1: thisvalue
    2: thatvalue
    3: anothervalue
    4: abc
    5: def
    6: ghi
"""

data = yaml.load(yaml_str, Loader=yaml.RoundTripLoader)
y = data['key']
print y.keys()[2:5]
print y.values()[2:5]
print y.items()[2:5]

to get:

[3, 4, 5]
['anothervalue', 'abc', 'def']
[(3, 'anothervalue'), (4, 'abc'), (5, 'def')]

without any special effort after loading the data.

The YAML specs state that the key ordering is not guaranteed, but in the YAML file they are of course ordered. If the parser doesn't throw this information awasy, things are much more useful e.g. for comparison between revisions of a file.

Fathead answered 3/8, 2015 at 21:29 Comment(5)
Pardon me, but how is your answer different then mine? XD Except that you are using a non-standard custom library, which makes the code not exactly portable.Wynn
As of summer 2015 there is nothing in the standard python library for reading YAML files, so a non-standard, custom, library is the only thing you can use (ruamel.yaml. PyYaml based on syck, libyaml). I've updated the answer to give you credit for the usage of YAML mappings. Please note that I am not relying on some after the fact making the keys ordered again as your proposal does, the mappings stay ordered on round-trip and also works if you have keys of the form1, 1a, ...9, 10, 10a, as well as any (random set of) keys that have to keep the order of the YAML file,Fathead
I forgot that PyYaml and libyaml are not part of the standard modules. facepalmWynn
@Wynn No problem, actually it is quite a pity IMO that there isn't and standard yaml module. But PyYAML currently not even being compatible with the latest spec in some areas, makes it currently not even a good candidate.Fathead
:-/ And all that considering how much YAML is used together with Python. I work with OpenCV, ROS etc. and all rely heavily on parsing YAML files. Hmpf, pity indeed.Wynn

© 2022 - 2024 — McMap. All rights reserved.