Indexing down multiple levels in Python - python

I know this is probably a pretty basic one, but I've looked and I can't find the answer.
I have a system running trees (nested dict objects) that can be of arbitrary depth.
At present, a subtree index is stored as a list of keys, so in the structure:
example = { 1 : "foo" ,
2 : { 2 : "bar" } ,
3 : { 3 : { 3 : "zip" } } }
the index of "foo" is [1], the index of "bar" is [2,2] and the index of "zip" is [3,3,3].
At the moment, I'm iterating through the list with a for loop :
pointer = root_of_tree
for index in index_list :
pointer = pointer[index]
This works pretty well, but it strikes me that Python is the sort of language that might have a built-in way of handling this case.
Is there a one-line solution? Perhaps a method of the iterable class?

Related

Python - remove json object if missing key

I'm looking to delete all objects from some JSON data if it is missing the key or value.
Here is a snippet of the JSON data:
[
{
"cacheId": "eO8MDieauGIJ",
"pagemap": {}
},
{
"cacheId": "AWYYu9XQnuwJ",
"pagemap": {
"cse_image": [
{
"src": "https://someimage.png"
}
]
}
},
{
"cacheId": "AWYYu9XQnuwJ",
"pagemap": {
"cse_image": [
{
}
]
}
}
]
I'm looking to delete the 1st and 3rd object in the data because the 1st object has an empty ['pagemap'] and the 3rd object has an empty ['pagemap']['cse_image']
Here is what I've tried so far without any luck:
for result in data[:]:
if result['pagemap']['cse_image'] == []:
data.remove(result)
for result in data[:]:
if result['pagemap'] == None:
data.remove(result)
for result in data[:]:
if len(result['pagemap']) == 0:
data.remove(result)
Thanks for the help!
Two things:
You don't want to remove elements from a list while iterating over them -- the memory you're removing is shifting as you're accessing it.
The third object has a nonempty ['pagemap']['cse_image']. Its value is a one-element list containing an empty dictionary. You need to index into the list to check whether or not the inner dictionary is empty.
With these two points in mind, here is an approach using filter() that also leverages the fact that empty data structures have falsy values:
result = list(filter(lambda x: x['pagemap'] and x['pagemap']['cse_image'] and x['pagemap']['cse_image'][0], data))
print(result)
If that data structure remains consistent, you can do it with a list comprehension.
[e for e in d if e["pagemap"] and e["pagemap"]["cse_image"] and any(e["pagemap"]["cse_image"])]
produces:
[{'cacheId': 'AWYYu9XQnuwJ', 'pagemap': {'cse_image': [{'src': 'https://someimage.png'}]}}]
Where d is your given data structure.

nested for loops and nested dictionary?

i am a new programmer trying to learn how to code still. I still don't quite know all of the technical info. I am trying to use a for loop on a list of dictionaries, and then inside of that loop, i want to create another loop that enumerates the dictionary keys. Inside of that loop, I then want to print the keys and values. I want the loop to break once the index reaches all of the points.
Dogs_in_Shelter = [{
"type" : "poodle",
"age" : "2",
"size" : "s",
},
{
"type" : "pug",
"age" : "7",
"size" : "m",
},
{
"type" : "lab",
"age" : "10",
"size" : "m",
}
]
for a in Dogs_in_Shelter:
for index, a in enumerate(Dogs_in_Shelter):
while (index <= 2):
print("{} {}".format(index,a["type"]))
index += 1
break
what prints out is:
0 poodle
1 pug
2 lab
0 poodle
1 pug
2 lab
0 poodle
1 pug
2 lab
I want only the first three lines (with the key and value) , not the repetitions.
Any help for a learner?
edit Yes there is an easier way without the nesting loops however i still need to have them nested. Thanks!
No need of extra for loop and while loop.
enumerate function gives you index and by passing type key you can get its value.
for index, a in enumerate(Dogs_in_Shelter):
print("{} {}".format(index, a["type"]))
Using nesting for loop.
Here I have used counter length = 0. Instead of while we should use if to check the counter.
length = 0
for a in Dogs_in_Shelter:
for index, a in enumerate(Dogs_in_Shelter):
if length <= 2 :
print("{} {}".format(index,a["type"]))
length += 1
You only need one for loop for what you want. while loop is also unnecessary. For example,
for index, dog in enumerate(Dogs_in_Shelter):
print(index, dog['type'])
For Python, we don't use upper letters for variables. FYI, Python Naming Convention
In this case, Dogs_in_Shelter should be dogs_in_shelter, or simply dogs.

Merging an array of json objects using python

I've got a python array of json objects that I instantiate simply by doing this:
results = []
I'm then doing an API call, and I assign the api_results['a_results'] to my array as follows:
api_results = api_func(url, session)
if loop = 0:
results.append(api_results['a_results']) #NB: The 'a_results' object here is an array of json
else:
results[0].append(api_results['a_results'])
objects
The first time this is called, everything works as expected:
[
[
{
object 1
},
{
object 2
}
]
]
However, if a certain number of results aren't found, the logic loops round again and I wish to append new results to the old object. This is where I'm having my issues.
The next iteration, the object looks like this:
[
[
{
old object 1
},
{
old object 2
},
[
{
new object 3
},
{
new object 4
}
]
]
]
So the array gets appended after object 2 as opposed to the actual objects.
Is there a way I can solve this issue? Essentially, when the threshold isn't met, I want an array of the 4 objects, as opposed to an array of the original 2 objects and then a sub array with 2 new objects.
I really want to append the objects within the array as opposed to the array I guess
Ok, so I've had some joy doing this:
if page == 0:
results.append(api_results['a_results'])
results = results[0]
else:
for i in api_results['a_results']:
results.append(i)
For each element in the second array, append the object (eg Object 3 and 4)
This gets rid of the unnecessary outer array object too.
This may not be the most efficient means of solving the problem though.

How to iterate over a python dictionary, setting the key of the dictionary as another dictionary's value

I come from a C++ background, I am new to Python, and I suspect this problem has something to do with [im]mutability.
I am building a JSON representation in Python that involves several layers of nested lists and dictionaries in one "object". My goal is to call jsonify on the end result and have it look like nicely structured data.
I hit a problem while building out an object:
approval_groups_list = list()
approval_group_dict = dict()
for groupMemKey, groupvals in groupsAndMembersDict.items():
approval_group_dict["group_name"] = groupMemKey
approval_group_dict["name_dot_numbers"] = groupvals # groupvals is a list of strings
approval_groups_list.append(approval_group_dict)
entity_approval_unit["approval_groups"] = approval_groups_list
The first run does as expected, but after, whatever groupMemkey is touched last, that is what all other objects mirror.
groupsAndMembersDict= {
'Art': ['string.1', 'string.2', 'string.3'],
'Math': ['string.10', 'string.20', 'string.30']
}
Expected result:
approval_groups:
[
{
"group_name": "Art",
"name_dot_numbers": ['string.1', 'string.2', 'string.3']
},
{
"group_name": "Math",
"name_dot_numbers": ['string.10', 'string.20', 'string.30']
}
]
Actual Result:
approval_groups:
[
{
"group_name": "Math",
"name_dot_numbers": ['string.10', 'string.20', 'string.30']
},
{
"group_name": "Math",
"name_dot_numbers": ['string.10', 'string.20', 'string.30']
}
]
What is happening, and how do I fix it?
Your problem is not the immutability, but the mutability of objects. I'm sure you would have ended up with the same result with the equivalent C++ code.
You construct approval_group_dict before the for loop and keep reusing it. All you have to do is to move the construction inside for so that a new object is created for each loop:
approval_groups_list = list()
for groupMemKey, groupvals in groupsAndMembersDict.items():
approval_group_dict = dict()
...
Through writing this question, it dawned on me to try a few things including this, which fixed my problem - however, I still don't know exactly why this works. Perhaps it is more like a pointer/referencing problem?
approval_groups_list = list()
approval_group_dict = dict()
for groupMemKey, groupvals in groupsAndMembersDict.items():
approval_group_dict["group_name"] = groupMemKey
approval_group_dict["name_dot_numbers"] = groupvals
approval_groups_list.append(approval_group_dict.copy()) # <== note, here is the difference ".copy()"
entity_approval_unit["approval_groups"] = approval_groups_list
EDIT: The problem turns out to be that Python is Pass by [object] reference all the time. If you are new to Python like me, this means: "pass by reference, except when the thing you are passing is immutable, then its pass by value". So in a way it did have to do with [im]mutability. Mostly it had to do with my lack of understanding how Python passes references.

Python - add a list of dictionary in a dictionary

So I have a dictionary called component and a list of dictionaries called allocations.
I want to be able to put the allocations under a component as a nested dictionary. kind of like so:
Allocations[
allocation1 : {
key : value
},
allocation2 {
key : value
}
]
My desired output:
Component1 : {
key:value
allocations : [allocation1 : {
key : value
}
,allocation2 : {
key : value
}
]
}
I came from Java, and i realize there is no append that I can use.
I tried this and obviously didnt work:
#allocate this under the selected component - DIDNT WORK
component["allocations"][] = allocation
How can I create a list of dictionaries in a dictionary?
Simply assign it:
component["allocations"] = some_list
For instance, if you want a new, empty one:
component["allocations"] = []
or:
component["allocations"] = list()
Then, manipulate the list as usual:
component["allocations"].append(some_object)

Categories