Pulling up "dict" value of nested JSON by one level - python

I'm looking at converting some Chef run_lists to tags, and would like to automate the process.
So far what I've done is created a variable that runs:
# write to file instead of directly to variable for archival purposes
os.system("knife search '*:*' -a expanded_run_list -F json > /tmp/hostname_runlist.json")
data = json.load(open('/tmp/hostname_runlist.json'))
From there, I have a dict within a dict with list values similar to this:
{u'abc.com': {u'expanded_run_list': None}}
{u'foo.com': {u'expanded_run_list': u'base::default'}}
{u'123.com': {u'expanded_run_list': [u'utils::default', u'base::default']}}
...
I would like to convert that to a more simpler dictionary by removing the 'expanded_run_list' portion, as it it's not required at this point, so in the end it looks like this:
abc.com:None
foo.com:'base::default'
123.com:['utils::default', 'base::default']
I would like to keep the values as a list, or a single value depending on what is returned. When I run a 'for statement' to iterate, I can pull the hostnames from i.keys, but would need to remove the expanded_run_list key from i.values, as well as pair the key values up appropriately.
From there, I should have an easier time to iterate through the new dictionary when running an os.system Chef command to create the new tags. It's been a few years since I've written in python, so am a bit rusty. Any descriptive help would be much appreciated.

Considering that you are having your list of dict objects as:
my_list = [
{u'abc.com': {u'expanded_run_list': None}},
{u'foo.com': {u'expanded_run_list': u'base::default'}},
{u'123.com': {u'expanded_run_list': [u'utils::default', u'base::default']}}
]
Then, in order to achieve your desired result, you may use a combination of list comprehension and dict comprehension as:
For getting the list of nested dictionary
[{k: v.get('expanded_run_list') for k, v in l.items()} for l in my_list]
which will return you the list of dict objects in your desired form as:
[
{u'abc.com': None},
{u'foo.com': u'base::default'},
{u'123.com': [u'utils::default', u'base::default']}
]
Above solution assumes that you only want the value of key 'expanded_run_list' to be picked up from each of your nested dictionary. In case it doesn't exists, dict.get will return None which will be set as value in your resultant dict.
For pulling up your nested dictionary to form single dictionary
{k: v.get('expanded_run_list') for l in my_list for k, v in l.items()}
which will return:
{
'foo.com': 'base::default',
'123.com': ['utils::default', 'base::default'],
'abc.com': None
}

Related

Change list according to dictionary items

Hello I have a list that looks like:
>>>ids
'70723295',
'75198124',
'140',
'199200',
'583561',
'71496270',
'69838760',
'70545907',
...]
I also have a dictionary that gives those numbers a 'name'. Now I want to create a new list that contains only the names, in the order like the numbers before.. so replace the numbers in the right order with the right names from the dictionary.
I tried:
with open('/home/anja/Schreibtisch/Master/ABA/alltogether/filelist.txt') as f:
ids = [line.strip() for line in f.read().split('\n')]
rev_subs = { v:k for v,k in dictionary.items()}
new_list=[rev_subs.get(item,item) for item in ids]
#dict looks like:
'16411': 'Itgax',
'241041': 'Gm4956',
'22419': 'Wnt5b',
'20174': 'Ruvbl2',
'71833': 'Dcaf7',
...}
But new_list is still the same as ids.
What am I doing wrong?
Maybe the dictionary keys are not in the format you think? Maybe the dictionary contains integers, meanwhile the ids are strings. I would investigate on that, it seems a mismatch of types more than an empty (or non-matching) dictionary.
Your dictionary keys are bs4.element.NavigableString objects rather than strings, so you cannot use strings as keys to look up its values.
You can fix this by converting the keys to strings when you build rev_subs:
rev_subs = {str(k): v for k, v in dictionary.items()}

Retrieve values from both nested dictionaries within a list

i'm using an api call in python 3.7 which returns json data.
result = (someapicall)
the data returned appears to be in the form of two nested dictionaries within a list, i.e.
[{name:foo, firmware:boo}{name:foo, firmware:bar}]
i would like to retrieve the value of the key "name" from the first dictionary and also the value of key "firmware" from both dictionaries and store in a new dictionary in the following format.
{foo:(boo,bar)}
so far i've managed to retrieve the value of both the first "name" and the first "firmware" and store in a dictionary using the following.
dict1={}
for i in result:
dict1[(i["networkId"])] = (i['firmware'])
i've tried.
d7[(a["networkId"])] = (a['firmware'],(a['firmware']))
but as expected the above just seems to return the same firmware twice.
can anyone help achive the desired result above
you can use defaultdict to accumulate values in a list, like this:
from collections import defaultdict
result = [{'name':'foo', 'firmware':'boo'},{'name':'foo', 'firmware':'bar'}]
# create a dict with a default of empty list for non existing keys
dict1=defaultdict(list)
# iterate and add firmwares of same name to list
for i in result:
dict1[i['name']].append(i['firmware'])
# reformat to regular dict with tuples
final = {k:tuple(v) for k,v in dict1.items()}
print(final)
Output:
{'foo': ('boo', 'bar')}

search through a nested dictionary and record the steps

say I have a dictionary like this:
profile = {'Person':{'name':['John'], 'Description':['smart']}}
I am looking for a piece of code that searches for 'John', and 'Description', but doesn't know where they are in the nested dictionary. I also want to the code to print something like this:
John is located in the value of profile['Person']
Description is located in the key of profile['Person']
How can I do that? Any help will be appreciated. Thank you
Learn how to iterate through a nested dictionary. In Python Dictionary, items() method is used to return the list with all dictionary keys with values. Indexing [ ] is used to access an element of a nested dictionary
profile = {'Person':{'name':['John'], 'Description':['smart']},'Person1':{'name':['John1'], 'Description':['smart1']}}
for p_id, p_info in profile.items():
for key in p_info:
if p_info[key][0] == "John":
print(p_info[key][0],"is located in the value of profile['",p_id,"']")
if p_info[key][0] == "smart":
print(p_info[key][0],"is located in the value of profile['",p_id,"']")

How to access a dict's values and delete them?

I have a Python dict stuffs with keys and values(list);
{'car':['bmw','porsche','benz'] 'fruits':['banana','apple']}
And I would like delete first value from cars: bmw and first value from fruits: banana
How can I access and delete them please? I have tried .pop(index), but it doesn't work...
You can create a new dictionary where you skip the first element using [1:]
stuffs = {'car':['bmw','porsche','benz'], 'fruits':['banana','apple']}
stuffs_new = {k:v[1:] for k,v in stuffs.items()}
# {'car': ['porsche', 'benz'], 'fruits': ['apple']}
An easy way of doing this is to use a for loop and iterate over each item in you're dictionary, and pop the first element:
dictionary = {'car':['bmw','porsche','benz'], 'fruits':['banana','apple']}
for key in dictionary:
dictionary[key].pop(0)
Or, as a list comprehension
dictionary = {'car':['bmw','porsche','benz'], 'fruits':['banana','apple']}
[dictionary[i].pop(0) for i in dictionary]
These pieces of code reference the dictionary at each of it's keys ('car' and 'fruits') and then proceeds to use pop on the values indexed by these keys.
Edit:
Don't use a list comprehension if you don't intend to store the list. In the case where you are iterating over large values, you could run into memory errors due to storing a whole load of useless values. Such as in this case:
[print(i) for i in range(9823498)]
This will store 9823498 None values*, where as a for loop would not. but still achieve the same thing.
You were almost there.
Use either:
del dict[key]
Or
dict.pop(key, value)
The second will remove but also leave the item available as a return

Python: How to traverse a List[Dict{List[Dict{}]}]

I was just wondering if there is a simple way to do this. I have a particular structure that is parsed from a file and the output is a list of a dict of a list of a dict. Currently, I just have a bit of code that looks something like this:
for i in xrange(len(data)):
for j, k in data[i].iteritems():
for l in xrange(len(data[i]['data'])):
for m, n in data[i]['data'][l].iteritems():
dostuff()
I just wanted to know if there was a function that would traverse a structure and internally figure out whether each entry was a list or a dict and if it is a dict, traverse into that dict and so on. I've only been using Python for about a month or so, so I am by no means an expert or even an intermediate user of the language. Thanks in advance for the answers.
EDIT: Even if it's possible to simplify my code at all, it would help.
You never need to iterate through xrange(len(data)). You iterate either through data (for a list) or data.items() (or values()) (for a dict).
Your code should look like this:
for elem in data:
for val in elem.itervalues():
for item in val['data']:
which is quite a bit shorter.
Will, if you're looking to decend an arbitrary structure of array/hash thingies then you can create a function to do that based on the type() function.
def traverse_it(it):
if (isinstance(it, list)):
for item in it:
traverse_it(item)
elif (isinstance(it, dict)):
for key in it.keys():
traverse_it(it[key])
else:
do_something_with_real_value(it)
Note that the average object oriented guru will tell you not to do this, and instead create a class tree where one is based on an array, another on a dict and then have a single function to process each with the same function name (ie, a virtual function) and to call that within each class function. IE, if/else trees based on types are "bad". Functions that can be called on an object to deal with its contents in its own way "good".
I think this is what you're trying to do. There is no need to use xrange() to pull out the index from the list since for iterates over each value of the list. In my example below d1 is therefore a reference to the current data[i].
for d1 in data: # iterate over outer list, d1 is a dictionary
for x in d1: # iterate over keys in d1 (the x var is unused)
for d2 in d1['data']: # iterate over the list
# iterate over (key,value) pairs in inner most dict
for k,v in d2.iteritems():
dostuff()
You're also using the name l twice (intentionally or not), but beware of how the scoping works.
well, question is quite old. however, out of my curiosity, I would like to respond to your question for much better answer which I just tried.
Suppose, dictionary looks like: dict1 = { 'a':5,'b': [1,2,{'a':100,'b':100}], 'dict 2' : {'a':3,'b':5}}
Solution:
dict1 = { 'a':5,'b': [1,2,{'a':100,'b':100}], 'dict 2' : {'a':3,'b':5}}
def recurse(dict):
if type(dict) == type({}):
for key in dict:
recurse(dict[key])
elif type(dict) == type([]):
for element in dict:
if type(element) == type({}):
recurse(element)
else:
print element
else:
print dict
recurse(dict1)

Categories