WILDCARD = object()
def iter_keys(obj):
try:
for k,v in obj.iteritems():
yield k
except AttributeError:
for idx, item in enumerate(obj):
yield idx
def iter_matching_key_sequences(obj, keys):
if not keys:
yield []
return
cur_key = keys[0]
rest = keys[1:]
if cur_key is WILDCARD:
for left in iter_keys(obj):
for right in iter_matching_key_sequences(obj[left], rest):
yield [left] + right
else:
try:
inner_obj = obj[cur_key]
except TypeError, KeyError:
return
for right in iter_matching_key_sequences(obj[cur_key], rest):
yield [cur_key] + right
d = {
"battletag": "corvid#1376",
"games": [{
"overwatch": {
"characters": [{
"_id": "1234",
}, {
"_id": "5678",
}]
}
}, {
"world of warcraft": {
"characters": [{
"_id": "234",
}]
}
}]
}
# integer name of game integer
# vvvvvvvv vvvvvvvv vvvvvvvv
for seq in iter_matching_key_sequences(d, ["games", WILDCARD, WILDCARD, "characters", WILDCARD, "_id"]):
print seq
V0lMRENBUkQgPSBvYmplY3QoKQoKZGVmIGl0ZXJfa2V5cyhvYmopOgogICAgdHJ5OgogICAgICAgIGZvciBrLHYgaW4gb2JqLml0ZXJpdGVtcygpOgogICAgICAgICAgICB5aWVsZCBrCiAgICBleGNlcHQgQXR0cmlidXRlRXJyb3I6CiAgICAgICAgZm9yIGlkeCwgaXRlbSBpbiBlbnVtZXJhdGUob2JqKToKICAgICAgICAgICAgeWllbGQgaWR4CgpkZWYgaXRlcl9tYXRjaGluZ19rZXlfc2VxdWVuY2VzKG9iaiwga2V5cyk6CiAgICBpZiBub3Qga2V5czoKICAgICAgICB5aWVsZCBbXQogICAgICAgIHJldHVybgoKICAgIGN1cl9rZXkgPSBrZXlzWzBdCiAgICByZXN0ID0ga2V5c1sxOl0KICAgIGlmIGN1cl9rZXkgaXMgV0lMRENBUkQ6CiAgICAgICAgZm9yIGxlZnQgaW4gaXRlcl9rZXlzKG9iaik6CiAgICAgICAgICAgIGZvciByaWdodCBpbiBpdGVyX21hdGNoaW5nX2tleV9zZXF1ZW5jZXMob2JqW2xlZnRdLCByZXN0KToKICAgICAgICAgICAgICAgIHlpZWxkIFtsZWZ0XSArIHJpZ2h0CiAgICBlbHNlOgogICAgICAgIHRyeToKICAgICAgICAgICAgaW5uZXJfb2JqID0gb2JqW2N1cl9rZXldCiAgICAgICAgZXhjZXB0IFR5cGVFcnJvciwgS2V5RXJyb3I6CiAgICAgICAgICAgIHJldHVybgogICAgICAgIGZvciByaWdodCBpbiBpdGVyX21hdGNoaW5nX2tleV9zZXF1ZW5jZXMob2JqW2N1cl9rZXldLCByZXN0KToKICAgICAgICAgICAgeWllbGQgW2N1cl9rZXldICsgcmlnaHQKCmQgPSB7CiAgImJhdHRsZXRhZyI6ICJjb3J2aWQjMTM3NiIsCiAgImdhbWVzIjogW3sKICAgICJvdmVyd2F0Y2giOiB7CiAgICAgICJjaGFyYWN0ZXJzIjogW3sKICAgICAgICAiX2lkIjogIjEyMzQiLAogICAgICB9LCB7CiAgICAgICAgIl9pZCI6ICI1Njc4IiwKICAgICAgfV0KICAgIH0KICB9LCB7CiAgICAid29ybGQgb2Ygd2FyY3JhZnQiOiB7CiAgICAgICJjaGFyYWN0ZXJzIjogW3sKICAgICAgICAiX2lkIjogIjIzNCIsCiAgICAgIH1dCiAgICB9CiAgfV0KfQoKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGludGVnZXIgICBuYW1lIG9mIGdhbWUgICAgICAgICAgICBpbnRlZ2VyCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2dnZ2dnZ2diAgdnZ2dnZ2dnYgICAgICAgICAgICAgICAgdnZ2dnZ2dnYKZm9yIHNlcSBpbiBpdGVyX21hdGNoaW5nX2tleV9zZXF1ZW5jZXMoZCwgWyJnYW1lcyIsIFdJTERDQVJELCBXSUxEQ0FSRCwgImNoYXJhY3RlcnMiLCBXSUxEQ0FSRCwgIl9pZCJdKToKICAgIHByaW50IHNlcQ==
['games', 0, 'overwatch', 'characters', 0, '_id']
['games', 0, 'overwatch', 'characters', 1, '_id']
['games', 1, 'world of warcraft', 'characters', 0, '_id']