2

I have a matrix:

matrix = {
    'A' : {
        'A1' : { 
            'A11' : [1,2,3],
            'A12' : [4,5,6],
        },
        'A2' : {
            'A21' : [11,12,14],
            'A22' : [14,15,16],
        },
        'A3' : {
            'A31' : [111,112,114],
            'A32' : [114,115,116],
        },
    }
}

and I want to retrieve particular paths that are dynamically queried -- such matrix['A']['A2']['A22'] or matrix['A']['A2'].

In simpler terms, I have a multi-level dictionary, and a list of strings that map to hierarchies in that dictionary. such as ['A','A1','A2']

I'm not sure the most pythonic way of doing this.

The following works. I'm just wondering if there is a more concise or readable way. I'd love another set of eyes to offer input and correct an obvious mistake.

get_target_path( pth , mtx ):
    try:
        value = mtx    
        for level in pth :
            value = value[level]
        return value
    except KeyError :
        return None

target_path = ['A','A2','A22']
result = get_target_path( target_path , matrix )
Jonathan Vanasco
  • 15,111
  • 10
  • 48
  • 72
  • 1
    i don't see anything wrong with what you already posted. you _could_ create a class that wraps a dict and does this internally so you could call matrix[mystring], but not sure it would be needed. – Corley Brigman Oct 01 '13 at 23:40

2 Answers2

7

A shorter option is:

import operator
from functools import reduce  # in python 3 only; reduce is a builtin in python 2

def get_target_path(path, matrix):
    try:
        return reduce(operator.getitem, path, matrix)
    except KeyError:
        return None

but I don't think it's really any better; I probably would have written it the way you did (though with different spacing :p).

Danica
  • 28,423
  • 6
  • 90
  • 122
4

I like the original fine. Any answer involving reduce is going to leave most code readers scratching their heads in despair (LOL - but there's a reason reduce is no longer dignified by being a built-in in Python 3). I'd just suggest cutting the "wordiness" of it:

def get_target_path(pth, mtx):
    for level in pth:
        mtx = mtx.get(level, None)
        if mtx is None:
            break
    return mtx
Tim Peters
  • 67,464
  • 13
  • 126
  • 132