Flattening a dictionary <str, list> into a comprehensive list - python

So I've got the following dictionary from a server request:
dict = {"first": "Mark", "last": "Zuckerberg", "alternative": ["Zuck", "Facebook guy"]}
Which I'm looking to convert into a list like this:
result = ["Mark", "Zuckerberg", "Zuck", "Facebook guy"]
I'm really trying to keep it pythonic for personal satisfaction I guess. The closest I've been to is this, which you can tell it only gives me the nested list instead of what I'm actually looking for.
values = list(dict.values())
result = [item for sublist in values for item in sublist if isinstance(sublist, list)]
Thanks for any input.

You could do:
def flatten(s):
for e in s:
if isinstance(e, (tuple, list)):
yield from flatten(e)
else:
yield e
d = {"first": "Mark", "last": "Zuckerberg", "alternative": ["Zuck", "Facebook guy"]}
result = list(flatten(d.values()))
print(result)
Output
['Mark', 'Zuckerberg', 'Zuck', 'Facebook guy']
The flatten function will deal with arbitrary nested lists.

Related

How can I classify the factors in the list using a dictionary in Python?

There is a list named lists and a dictionary labeled categories.
lists = ["Ferrari", "Rose", "Samsung", "Porsche"]
categories = {"car": {"Ferrari", "Porsche"}, "flower": {"Rose", "Chamomile"}, "phone": {"Apple", "Samsung"}}
I would like to get a dictionary return with the names given in the list as key and the classification of the names as value.
like this.
{"Ferrari": "car", "Rose": "flower", "Samsung": "phone", "Porsche": "car"}
and this is my code, but it doesn't work.
def classify(lists: list, categories: dict):
result = {}
for i in range(len(lists)):
if lists== categories.keys():
result[lists] = categories.keys()
return result
You can do it this way, using two for loops, I just did small changes to your existing classify function.
Note: In your existing code, when you iterate using a single for loop and comparing lists==categories.keys() then it is doing like this ['Ferrari', 'Rose', 'Samsung', 'Porsche'] == dict_keys(['car', 'flower', 'phone']) which is wrong that's why it will not work as you required.
lists = ["Ferrari", "Rose", "Samsung", "Porsche"]
categories = {"car": {"Ferrari", "Porsche"}, "flower": {"Rose", "Chamomile"}, "phone": {"Apple", "Samsung"}}
def classify(lists: list, categories: dict):
result = {}
for i in range(len(lists)):
for k, v in categories.items():
if lists[i] in v:
result[lists[i]] = k
return result
print(classify(lists, categories))
Output:
{'Ferrari': 'car', 'Rose': 'flower', 'Samsung': 'phone', 'Porsche': 'car'}
To do this efficiently, you can create a reverse mapping that maps items to respective categories, so that you can create the new dict by iterating over the list and mapping each item to its category with the aforementioned mapping:
mapping = {item: category for category, items in categories.items() for item in items}
result = {item: mapping[item] for item in lists}
Demo: https://replit.com/#blhsing/SeashellHatefulWorkers
More efficiently you can use the below approach
lists = ["Ferrari", "Rose", "Samsung", "Porsche"]
categories = {"car": {"Ferrari", "Porsche"}, "flower": {"Rose", "Chamomile"}, "phone": {"Apple", "Samsung"}}
new_dict = dict.fromkeys(lists, "")
for k,v in categories.items():
t = dict.fromkeys(v, k)
new_dict.update(t)
print({k: new_dict.get(k, "") for k in lists})

How to a key recursively in a dictionary and return it's value

I have a nested dictionary like below
dictionary = {"name": "Stephen", "language": "English", "address": "13 Aust road", "teacher_info": [{"name": "Alan", "language": "Italian"}]}
I want to return the languages.
Output = ["English", "Italian"]
What have I tried
output = []
for i, j in dictionary.items():
if i == "language":
output.appened(j)
For things like this recursion is your friend. The following function will find keys called language and add their value to the list.
If any of the items in the dictionary is itself a dictionary we do the same thing. We concatenate the languages found in the nested dictionary to the list at the top level.
The base case for a dictionary without any languages is an empty list.
def get_languages(dictionary):
output = []
for key, value in dictionary.items():
if key == "language":
output.appened(value)
elif isinstance(value, dict):
output += get_languages(value)
return output

Get parent(key) from value (an element stored in a list)

I am stuck in a problem wherein I have to find the common 'parent' of items in a list.
Here's the problem-
I have a reference file - hierarchy.json, and this file is loaded as a dictionary in my super class.
{
"DATE": ["ISO", "SYSTEM", "HTTP"],
"IP": ["IPv4", "IPv6"],
"PATH": ["UNIX", "WINDOWS"]
}
As an input, I get a list of values and I expect to get a set of elements, which belong to the same parent (referring to the hierarchy.json file) as an output. Even better, if I could get the parent name, that would be great.
input_list = ["ISO", "UNIX", "HTTP"]
result = do_something(input_list)
print('RESULT:\t', result)
>>> RESULT: set("ISO","HTTP")
Essentially, I want to make sets of the elements which belong to different "parents" in the element.
I know this can be done O(n^3) by looping through each element of the list. This is obviously not the best way to achieve the result.
Here's what I have tried -
def do_something(input_list: list, reference_dir: dict) -> list:
result_list = []
for lists in reference_dir.values():
results = []
for i in input_list:
for j in input_list:
if i != j:
if set([i,j]).issubset(set(lists)):
results.extend(set([i,j]))
result_list.append(set(results))
return result_list
input_list = ["ISO", "UNIX", "HTTP", "SYSTEM","WINDOWS"]
reference_dir = {"DATE": ["ISO", "SYSTEM", "HTTP"],"IP": ["IPv4", "IPv6"],"PATH":["UNIX", "WINDOWS"]}
result = do_something(input_list, reference_dir)
print('RESULT:\t', (result))
>>> RESULT: [{'SYSTEM', 'HTTP', 'ISO'}, set(), {'UNIX', 'WINDOWS'}]
Is there a way to optimize this/implement this in a better way?
Edited (Added) ->
ALSO,
if there's a way I could get the name of the 'parent' as the output, that would be AWESOME.
>>> RESULT: [DATE, PATH]
Thanks.
def do_something(input_list: list, reference_dir: dict) -> list:
sets_1 = {k: set() for k in reference_dir.keys()}
sets_2 = {item: sets_1[k] for k, list in reference_dir.items() for item in list}
for input in input_list:
sets_2[input].add(input)
return sets_1
reference_dir = {
"DATE": ["ISO", "SYSTEM", "HTTP"],
"IP": ["IPv4", "IPv6"],
"PATH": ["UNIX", "WINDOWS"]
}
input_list = ["ISO", "UNIX", "HTTP"]
print(do_something(input_list, reference_dir))
Prints:
{'DATE': {'HTTP', 'ISO'}, 'IP': set(), 'PATH': {'UNIX'}}
What do_something does:
sets_1 = {k: set() for k in reference_dir.keys()} This line creates a dictionary where each key is a key form reference_dir and the value is an empty set.
sets_2 = {item: sets_1[k] for k, list in reference_dir.items() for item in list} This line creates another dictionary. The keys are the elements of the lists which are the values of the reference_dir dictionary and the value for each key is the corresponding empty set created in step 1 associated with the lists owning key.
for input in input_list: sets_2[input].add(input) Each element of input_list is added to appropriate set using the dictionary created in step 2 to select the correct set.
return sets_1 This returns a dictionary whose keys are all the keys in reference_dir and whose values are now the filled in sets (some of which might be empty). The keys are the "names" of the sets you were looking for.
See Demo

Issues iterating through JSON list in Python?

I have a file with JSON data in it, like so:
{
"Results": [
{"Id": "001",
"Name": "Bob",
"Items": {
"Cars": "1",
"Books": "3",
"Phones": "1"}
},
{"Id": "002",
"Name": "Tom",
"Items": {
"Cars": "1",
"Books": "3",
"Phones": "1"}
},
{"Id": "003",
"Name": "Sally",
"Items": {
"Cars": "1",
"Books": "3",
"Phones": "1"}
}]
}
I can not figure out how to properly loop through the JSON. I would like to loop through the data and get a Name with the Cars for each member in the dataset. How can I accomplish this?
import json
with open('data.json') as data_file:
data = json.load(data_file)
print data["Results"][0]["Name"] # Gives me a name for the first entry
print data["Results"][0]["Items"]["Cars"] # Gives me the number of cars for the first entry
I have tried looping through them with:
for i in data["Results"]:
print data["Results"][i]["Name"]
But recieve an error:
TypeError: list indices must be integers, not dict
You are assuming that i is an index, but it is a dictionary, use:
for item in data["Results"]:
print item["Name"]
Quote from the for Statements:
The for statement in Python differs a bit from what you may be used to in C or Pascal. Rather than always iterating over an arithmetic progression of numbers (like in Pascal), or giving the user the ability to define both the iteration step and halting condition (as C), Python’s for statement iterates over the items of any sequence (a list or a string), in the order that they appear in the sequence.
you are iterating through the dictionary not indexes so you should either use.
for item in data["Results"]:
print item["Name"]
or
for i in range(len(data["Results"])):
print data["Results"][i]["Name"]
The confusion is in how dictionaries and lists are used in iteration.
A dictionary will iterate over it's keys (which you use as indices to get corresponding values)
x = {"a":3, "b":4, "c":5}
for key in x: #same thing as using x.keys()
print(key,x[key])
for value in x.values():
print(value) #this is better if the keys are irrelevant
for key,value in x.items(): #this gives you both
print(key,value)
but the default behaviour of iterating over a list will give you the elements instead of the indices:
y = [1,2,3,4]
for i in range(len(y)): #iterate over the indices
print(i,y[i])
for item in y:
print(item) #doesn't keep track of indices
for i,item in enumerate(y): #this gives you both
print(i,item)
If you want to generalize your program to handle both types the same way you could use one of these functions:
def indices(obj):
if isinstance(obj,dict):
return obj.keys()
elif isinstance(obj,list):
return range(len(obj))
else:
raise TypeError("expected dict or list, got %r"%type(obj))
def values(obj):
if isinstance(obj,dict):
return obj.values()
elif isinstance(obj,list):
return obj
else:
raise TypeError("expected dict or list, got %r"%type(obj))
def enum(obj):
if isinstance(obj,dict):
return obj.items()
elif isinstance(obj,list):
return enumerate(obj)
else:
raise TypeError("expected dict or list, got %r"%type(obj))
this way if you, for example, later changed the json to store the results in a dict using the id as keys the program would still iterate through it the same way:
#data = <LOAD JSON>
for item in values(data["Results"]):
print(item["name"])
#or
for i in indices(data["Results"]):
print(data["Results"][i]["name"])
for json_data in data['Results']:
for attribute, value in json_data.iteritems():
print attribute, value # example usage

iterate list and compare it's values with dict

I am dealing with 1. list of dictionaries and 2. list. I am trying to:
1. iterate through list (list1),
2. Match the list1's value with the ID of API response, if found- put entire dict in a new_dict
3. else skip
API response in Json format:
list_of_dict=[{"id":1500,
"f_name": "alex",
"age": 25
},
{"id" :1501,
"f_name":"Bob",
"age": 30
},
{"id" :1600,
"f_name":"Charlie",
"age": 35
}
...
]
And a list1:
list1=[1500,1501,1211.....]
According to this, 1500 & 1501 is present in list_of_dict so that entire dict will be added in new_dict.
My attempt:
new_dict=dict()
for i,val in enumerate(list1):
#assuming val found in dict
#so put it in new dict
print i ,"=",val
new_dict.update({"id": val,"name":name, "age":age})
What i see is this code taking only last item of the list and updates the dict.. but in my case, new_dict will contains two dictionaries with id 1500 and 1501. What i am missing?
list_of_dict = [{"id":1500,
"f_name": "alex",
"age": 25
},
{"id" :1501,
"f_name":"Bob",
"age": 30
},
{"id" :1600,
"f_name":"Charlie",
"age": 35
}
]
list1=[1500,1501,1211]
ret = filter(lambda x: x['id'] in list1, list_of_dict)
print ret
Check out the useful and simple filter function built-in to python. It iterates through an iterable (list) and returns only the items that return true for the provided function
In this case, our filtering function is:
lambda x: x['id'] in list1
list_of_dict = [{"id":1500,
"f_name": "alex",
"age": 25
},
{"id" :1501,
"f_name":"Bob",
"age" 30
},
{"id" :1600,
"f_name":"Charlie",
"age" 35
}
...
]
dicts = {d['id']:d for d in list_of_dict}
list1=[1500,1501,1211.....]
answer = [dicts[k] for k in list1 if k in dicts]
You can do this with a simple list comprehension, filtering the dicts by whether their id is in the list:
result = [d for d in list_of_dict if d["id"] in list1]
If your list1 is larger, you might want to turn it into a set first, so the lookup is faster:
list1_as_set = set(list1)
result = [d for d in list_of_dict if d["id"] in list1_as_set]

Categories

Resources