Home > database >  Python access list inside nested dictionary with index numbers only (no text)
Python access list inside nested dictionary with index numbers only (no text)

Time:11-10

1st off...this example is purely theoretical and is not to be considered 'best practice', this is merely a 'can this be done?' scenario, not a 'should this be done?' scenario.

Let's for argument's sake assume I have a list inside a nested dictionary...

Dictionary = {Planets:'none',
              Fruits:'none',
              Colors:{ColorList:['Red','Green','Blue']}}

And I would like to navigate directly to the list, without explicitly typing out the keys, using external modules or a for loop. If possible, how would I go about doing this?

I'm looking for something like...

List = Dictionary[2][1]
List = Dictionary.iloc[:,2].iloc[:,1]

Whereas...

List = Dictionary['Colors']['ColorList']

Would be considered illegal.

Thanks in advance...

CodePudding user response:

The first point is that "without using external modules" is kind of a moot point since the ordering of keys in a dictionary is not guaranteed unless you are using collections.OrderedDict, so the first thing I will do is drop that requirement.

If you want a solution that uses a loop (I know you asked for none of that either) then it isn't too complicated:

import collections
Dictionary = collections.OrderedDict([
    ('Planets','none'),
    ('Fruits','none'),
    ('Colors',collections.OrderedDict([('ColorList',['Red','Green','Blue'])]))])

def dict_index_with_num(d, numeric_idx):
    for idx, v in enumerate(d.values()):
        if idx == numeric_idx:
            return v
    raise IndexError("dict index out of range")

# correctly extracts the list with numbers probably not useful
print(dict_index_with_num(dict_index_with_num(Dictionary,2), 0))

However I assume your notion of not wanting to use a loop was that for large dictionaries that can be slow, so instead you can use itertools.islice to skip the iteration (except this still breaks your requirement of no external modules)

import itertools

def dict_index_with_num(d,numeric_idx):
    try:
        return next(itertools.islice(d.values(), numeric_idx, None))
    except StopIteration:
        pass # will raise a seperate IndexError without nested exceptions
    raise IndexError("dict index out of range")

# correctly extracts the list with numbers, again not very useful
print(dict_index_with_num(dict_index_with_num(Dictionary,2), 0))

This is now efficient for large dictionaries and high indices, however it is still annoying that you have to use a separate function call for each indexing, it isn't nearly as convinient as Dictionary[2][0] so we can write a function that takes a list of indices and does the indexing in one go (except this is now using both a loop and external module, scandalous!)

def dict_index(d,*path):
    result = d
    for numeric_idx in path:
        # I'm just going to ignore decent error handling here
        result = next(itertools.islice(result.values(), numeric_idx, None))
    return result
# this is easier to work with but probably still not what you actually want
print(dict_index(Dictionary,2,0))

I am assuming none of this is actually helpful for your actual case, it would be really helpful to have a clearer goal than the current question of "how can I do <X> without <arbitrary restrictions>." Some clarification on what your goal is, why string keys should not be used but also keep the data structure in terms of string keys, would be really helpful to give you a more satisfactory answer. I hope this helps either your coding or in how you need to clarify your question. :)

CodePudding user response:

I figured out a method which converts each level to a list, not exactly what I was looking for but it'll do for my purpose.

I ended up going for...

List = list(list(Dictionary.values())[2].values())[1]

I realize this is not to be done blindly, as dictionary ordering will be an issue, regardless...it works for my case, as I can guarantee the ordering of my dictionary.

  • Related