How to get all keys and values in list of Nested dictionaries? - python-3.x

di = [{ "k": [1, 3, 5], "k1": { "k10" : 4, "k11": [4, 7, 9], "k12" : { "k120" : { "k121" : "v121" }}, "k14" : 6}}, {"k22": { "k221" : "v122"}}]
key_list = list()
val_list = list()
for i in di:
key_list.extend(i.keys())
val_list.extend(i.values())
for i in val_list:
if "dict" in str(type(i)):
key_list.extend(i.keys())
val_list.remove(i)
val_list.extend(i.values())
for i in val_list:
if "dict" in str(type(i)):
key_list.extend(i.keys())
val_list.remove(i)
val_list.extend(i.values())
print("Key list: ",key_list)
print("Vlaue list: ", val_list)
"""This is giving my answer but i need a optimised way and also for N nested dictionary how to get all keys and values, I need get all keys in a list and all values in a list."""

About optimization: If there is a reason of existing hierarchy there is not "optimised way" to disrespect the hierarchy, otherwise a real optimization needs to include a change not to construct the hierarchy that would be disrespected later.
I wrote the following, is not optimized but decently efficient and concise, it does something in the direction of what you imprecisely asked: (I let you refine what you intend to be returned, I noticed that you silently excluded to return those value whose type is dictionary, I didn't make such discrimination). To help to understand the flexibility of the code I made some examples as cases controlled by the behavioral variable bkv, this behavioral variable can be squeezed when you know what you want to obtain.
dictype=type({})
listype=type([])
def through(ref,bkv):
""" bkv in binary 01=1 yield key
10=2 yield value
11=3 yield (key,value) """
if type(ref)==listype:
for x in ref:
yield from through(x,bkv)
elif type(ref)==dictype:
for kv in ref.items():
if bkv==1:
yield kv[0]
elif bkv==2:
yield kv[1]
elif bkv==3:
yield kv
else:
throw(TypeError, "Not implemented")
yield from through(kv[1],bkv)
di = [
{ "k": [1, 3, 5],
"k1": { "k10" : 4,
"k11": [4, 7, 9],
"k12" : { "k120" : { "k121" : "v121" }},
"k14" : 6}},
{"k22": { "k221" : "v122"}}
]
list_keys=[x for x in through(di,1)]
list_values=[x for x in through(di,2)]
list_keyval=[x for x in through(di,3)]
print("Key list: ",list_keys)
print("Values list (all, not excluding dict values): ",list_values)
print("all (Key,Value) pairs:", list_keyval)

Related

How to sort a dictionary of nested lists by value with one key ascending and one key descending?

I'm working on a problem that states the following:
Write a function telling apart accepted and refused students according to a threshold.
The function should be called select_student and takes as arguments:
A list where each element is a list of a student name, and his mark.
A mark. The student mark must be superior or equal to the given mark to be accepted.
Your function must return a dictionary with two entries:
Accepted which list the accepted students sorted by marks in the descending order.
Refused which list the refused students sorted by marks in ascending order.
Example
In [1]: from solution import select_student
In [2]: my_class = [['Kermit Wade', 27], ['Hattie Schleusner', 67], ['Ben Ball', 5], ['William Lee', 2]]
In [3]: select_student(my_class, 20)
Out[3]:
{'Accepted': [['Hattie Schleusner', 67], ['Kermit Wade', 27]],
'Refused': [['William Lee', 2], ['Ben Ball', 5]]}
In [4]: select_student(my_class, 50)
Out[4]:
{'Accepted': [['Hattie Schleusner', 67]],
'Refused': [['William Lee', 2], ['Ben Ball', 5], ['Kermit Wade', 27]]}
My code is:
from collections import OrderedDict
students = [
["Kermit Wade", 27],
["Hattie Schleusner", 67],
["Ben Ball", 5],
["William Lee", 2],
]
def select_student(students, threshold):
output = {
'Accepted' : [],
'Refused' : []
}
for i in range(len(students)):
if students[i][1] >= threshold:
output['Accepted'].append(students[i])
elif students[i][1] < threshold:
output['Refused'].append(students[i])
return output
My output is:
{'Accepted': [['Kermit Wade', 27], ['Hattie Schleusner', 67]], 'Refused': [['Ben Ball', 5], ['William Lee', 2]]}
The output is for these parameters
print(select_student(students, 20))
As you can see I need to reverse the order for both accepted and refused. So Hattie comes first in accepted and then William comes first in refused.
I tried to use OrderedLists and googling but because of the nested list structure required by the problem I could not find a way to sort by the grade nor could I find a way to have it both be ascending and descending depending on the dictionary's key.
Thanks in advance!
Modify your select student function to sort your accepted and refused lists as follows:
def select_student(students, threshold):
output = {
'Accepted' : [],
'Refused' : []
}
for i in range(len(students)):
if students[i][1] >= threshold:
output['Accepted'].append(students[i])
elif students[i][1] < threshold:
output['Refused'].append(students[i])
output['Accepted'] = sorted(output['Accepted'], key= lambda x: x[1], reverse= True)
output['Refused'] = sorted(output['Refused'], key = lambda x: x[1])
return output

Python function removing items form list, dropping unexpected elements

It's a simple code practice challenge that asks that I make a function that takes a list of mixed types and returns only the integers
def return_only_integer(lst):
for i in lst:
if type(i) != int:
lst.remove(i)
return lst
That's it, it seems simple enough but the tests are coming back negative:
return_only_integer([9, 2, "space", "car", "lion", 16])
Returns: [9, 2, 'car', 16]
return_only_integer(["hello", 81, "basketball", 123, "fox"])
Returns what it should: [81, 123]
return_only_integer([10, "121", 56, 20, "car", 3, "lion"])
Also returns what it should: [10, 56, 20, 3]
but:
return_only_integer(["String", True, 3.3, 1])
Returns: [True, 1]
The code is so simple and straightforward, I have no idea why these 2 tests are failing.
Why would 'car' even be in the first list but the other strings not?
type(True) is bool, why is it there?
This is probably due to you modifying the list in the conditional. By removing an item from the list, you are likely shifting the iteration in that operation.
It may be worth looking into filter() instead.
https://docs.python.org/3/library/functions.html#filter
You can create a temporary list inside your function to hold the items that are integers. Once you have processed all the items, you can return the temporary list as part of your return statement. If there are no integers, you can return None.
def return_only_integer(lst):
int_lst = []
for i in lst:
if type(i) == int:
int_lst.append(i)
return int_lst if int_lst else None
print (return_only_integer([9, 2, "space", "car", "lion", 16]))
print (return_only_integer(['ball', True, "space", "car", "lion", 'fish']))
This will output as follows:
[9, 2, 16]
None
def return_only_integer(lst):
for i in lst:
if type(i) != int:
lst.remove(i)
return lst
THIS FUNCTION HAS VERY BIG FAULT.
consider this list [9, 2, "space", "car", "lion", 16]
when it had removed "space" then your i had directly reached to lion and it ignored car because your list is changed and your i index is not changed. so it is moving as it is.
after removing one non integer, you must make sure to change the index position of i. so try this code. it will work.
def return_only_integer(lst):
for i in lst:
#print(i,type(i))
if type(i) != int:
#print("flag this is not integer ",i)
lst.remove(i)
return_only_integer(lst)
return(lst)
print(return_only_integer(["hello", 81, "basketball", 123, "fox"]))
hope u understand. if you didn't understand then tell me .
Indeed you should not change the list you are iterating on, it produces unexpected results. Item deleted leaves room for the next, without the latter being picked in the iteration (so not being dropped in your example).
The possible choices to perform such task involve the usage of another list. A possible solution is very familiar to python developers:
def return_only_integer(lst):
return [i for i in lst if type(i) == int]

Find the intersection of dict of dicts based on the rules in python3.x

I have two dictionaries as given below and want to find the intersection of dictionaries based on some logic.
dict1= {"1":{"score1": 1.099, "score2":0.45},
"2": {"score2": 0.099, "score3":1.45},
"3": {"score2": 10, "score3":10.45}}
dict2= {"1":{"score6": 1.099, "score2":0.45},
"2": {"score2": 10, "score3":10.45},
"4": {"score5": 8, "score8":15}}
I want to create the dictionary based on the given two dictionaries based on the below rules:
1.union of the two dicitonaries based on the outer key
if outer key is common in both the dictionaries then in the nested key-value pair show only the common key with highest value across both the dictionaries.
result_dict = {"1":{"score2":0.45},
"3": {"score2": 10, "score3":10.45},
"2": {"score2": 10, "score3":10.45},
"4": {"score5": 8, "score8":15}}```
First off, thanks for providing concrete examples of what your inputs are like and what you'd like the output to look like.
There may well be more efficient ways of doing this, but since there's no mention of any constraints on performance, my first instinct was to turn to Python's set operations to make things a little simpler:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
dict1 = {
"1": {
"score1": 1.099,
"score2": 0.45
},
"2": {
"score2": 0.099,
"score3": 1.45
},
"3": {
"score2": 10,
"score3": 10.45
}
}
dict2 = {
"1": {
"score6": 1.099,
"score2": 0.45
},
"2": {
"score2": 10,
"score3": 10.45
},
"4": {
"score5": 8,
"score8": 15
}
}
result_dict = {
"1": {
"score2": 0.45
},
"3": {
"score2": 10,
"score3": 10.45
},
"2": {
"score2": 10,
"score3": 10.45
},
"4": {
"score5": 8,
"score8": 15
}
}
def weird_union(d1, d2):
"""Applies the logic in OP's question
Args:
d1 (dict): dict with one level of nested dicts as values
d2 (dict): dict with one level of nested dicts as values
Returns: dict
"""
result = {}
k1, k2 = set(d1.keys()), set(d2.keys())
# no collisions-- easy case
for k in k1.symmetric_difference(k2):
result[k] = d1[k] if k in d1 else d2[k]
# key appears in both dicts
for k in k1.intersection(k2):
_k1, _k2 = set(d1[k].keys()), set(d2[k].keys())
result[k] = {
key: max([d1[k][key], d2[k][key]])
for key in _k1.intersection(_k2)
}
return result
test = weird_union(dict1, dict2)
assert result_dict == test
print('Test passed.')
The basic idea is to treat the disjoint and the intersection cases separately. Hope this helps.
Update in response to comment:
In the future, please provide this sort of context up front; an operation on two dictionaries is rather different than an operation on an arbitrary number of inputs.
Here's one way to do it:
def invert_dicts(*dicts):
""" Takes multiple dicts and returns a dict mapping
key to dict index. E.g.,
invert_dicts(
{'a': 1, 'b': 2},
{'a': 3, 'c': 4}
)
returns
{'a': [0, 1], 'b': [0], 'c': [1]}
"""
key_map = {}
for i, d in enumerate(dicts):
for k in d.keys():
key_map.setdefault(k, []).append(i)
return key_map
def weird_n_union(*dicts):
"""Applies the logic in OP's question to an arbitrary number of inputs
>>> weird_n_union(d1, d2, ..., dn)
Args:
*dicts (dict): dictionaries w/one level of nested dicts as values
Returns: dict
"""
result = {}
# dict mapping key to list of dict index in `dicts` containing key
key_map = invert_dicts(*dicts)
for k in key_map:
# no outer key collision
if len(key_map[k]) == 1:
result[k] = dicts[key_map[k][0]][k]
# outer key collision
else:
# unclear what should happen in the case where:
# - there is an outer key collision
# - there are no shared sub-keys
#
# this implementation assumes that in that case, the value for k is {}
result.setdefault(k, {})
sub_dicts = tuple(dicts[i][k] for i in key_map[k])
# map keys in `sub_dicts` to indices for `dicts` containing key
sub_key_map = invert_dicts(*sub_dicts)
# contains elements of (k, v), where k appears in > 1 sub-dicts
shared_keys_only = filter(lambda kv: len(kv[1]) > 1,
sub_key_map.items())
# update result with the max value for each shared key
for kv in shared_keys_only:
max_ = max(((kv[0], sub_dicts[i][kv[0]]) for i in kv[1]),
key=lambda x: x[1])
result[k].update({max_[0]: max_[1]})
return result
Tried to annotate to make it a bit clear how things work. Hopefully this works for your use case.

Dictionary using distinct characters as values

I need to make a dictionary using the string list as keys and their distinct characters as values.
I have tried some functions and ended up with the following code but I cannot seem to add the string key into it
value=["check", "look", "try", "pop"]
print(value)
def distinct_characters(x):
for i in x:
yield dict (i=len(set(i)))
print (list(distinct_characters(value))
I would like to get
{ "check" : 4, "look" : 3, "try" : 3, "pop" : 2}
but I keep getting
{ "i" : 4, "i" : 3, "i" : 3, "i" : 2}
Well, string is itself an iterable, so don't call list on dicts instead call dict on list of tuples like below.
value=["check", "look", "try", "pop"]
print(value)
def distinct_characters(x):
for i in x:
yield (i, len(set(i)))
print(dict(distinct_characters(value)))
Output:
{'check': 4, 'look': 3, 'try': 3, 'pop': 2}
Consider the simple dictionary comprehension:
value = ["check", "look", "try", "pop"]
result = {key: len(set(key)) for key in value}
print(result)
Thanks for the replies
I needed to answer it as a function for a class exercise so I ended up using this code:
value=["check", "look", "try", "pop"]
print(value)
def distinct_characters(x):
for i in x:
yield (i, len(set(i)))
print(dict(distinct_characters(value)))
Thanks again

Groovy map : get the count of value that a key holds

I have a map,
def map= [name:[Vin], email:[vin#gmail.com], phone:[9988888888], jobTitle:[SE]]
i want get the total number of values that a key holds
for ex,
key name can have many values like [name:[Vin,Hus,Rock] how to do it programatically?
def count = map.name.size() //gives wrong answer
You can use the following code to get a list of size for all key.
def map= [name:['Vin',''], email:['vin#gmail.com'], phone:['9988888888'], jobTitle:['SE']]
map.collect{it.value.size()}
Output:
[2, 1, 1, 1]
I think map.name.size() should work fine too in groovy.
def map= [name :['Vin', 'abc', 'xyz'],
email:['vin#gmail.com'],
phone:[9988888888],
jobTitle:['SE']]
//Spread operator to get size of each value
assert map.values()*.size == [3, 1, 1, 1]
//Implicit spread
assert map.values().size == [3, 1, 1, 1]
//use size() to get the size of the values collection
assert map.values().size() == 4
//Values
assert map.values() as List == [['Vin', 'abc', 'xyz'],
['vin#gmail.com'], [9988888888], ['SE']]

Resources