How to extract the values from the dictionary with condition - python

My dictionary is below, if the values end with csv or json i need to put in another dictionary of same dictionary:
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
Code is below:
d = {}
for k,v in d.items():
for i in v:
if i.split('.')[1] == 'csv' or i.split('.')[1] == 'json':
d[k] = v
My out
{'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
Expected out
{'a': ['1.json', '1.csv'], 'B': ['2.json', '2.csv']}

You never change v, so the dictionary is unchanged. You should build a new list only keeping the wanted values:
for k,v in d.items():
v = [i for i in v if i.split('.')[1] in ('csv', 'json')]
d[k] = v
or even better:
d = {k: [i for i in v if i.split('.')[1] in ('csv', 'json')]
for k,v in d.items()}

You can try to use rfind to find the last . in the file name and to add it the list if it's matching CSV or JSON
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
for k, v in d.items():
d[k] = []
for i in v:
if i[i.rfind(".") + 1:] in ('csv', 'json'):
d[k].append(i)

Please test it:
from collections import defaultdict
x = defaultdict(list)
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
for k, v in d.items():
for i in v:
if i.split('.')[-1] in ['csv', 'json']:
x[k].append(i)
print(dict(x))

You can use dict comprehension with list comp on each of the values while filtering with str.endswith.
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
new = {k:[i for i in v if i.endswith(('.csv','.json'))] for k,v in d.items()}
# {'a': ['1.json', '1.csv'], 'B': ['2.json', '2.csv']}

A simple solution would be the following, assuming you want to update the existing dictionary
for k, v in d.items():
for i in v:
if i.rsplit('.')[-1] not in {'csv','json'}:
v.remove(i)

You can use split filename and add condition for checking the file type (using list for comparison could be a better option if you want to add more file types).
Combine this with list Comprehension, which provides a concise way to create lists.
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
filtered_d = {key:[item for item in value if item.split('.')[-1] in ['json','csv']] for key, value in d.items()}
you can check documentation here for more detail on list comprehension.

Related

Nested Dictionary Python:Update logic failing

My dictionary :
d={'a':'a1,a2,a3,a4','b':'b1,b2,b3,b4',c:'c1,c2,c3,c4'}
and so on d,e,f,....
d2={'a1':'a11,a12,a13,a14,a15','a2':'a21,a22,a23,a24,a25'}
and so on for a3,a4,a5,b1,b2....
Expected output
dict1={'a':{'a1':'a11,a12,a13,a14,a15','a2':'a21,a22,a23,a24,a25'}}
and so on for rest
My Output
dict1={'a':{'a1':'a11,a12,a13,a14,a15'},'a2':'a21,a22,a23,a24,a25'}
and so on then again
'b':{'b1':'b11,b12,b13,b14,b15'},'b2':'b21,b22,b23,b24,b25'}
My Code:
dict1={}
for i in d:
q=d[i].split(",")
for j in q:
dict1[i] = {}
if j in d2:
dict1[i][j] = d2[j]
dict1.update(dict1[i])
Any help would be very useful
You can try nested dictionary comprehension with list comprehension
d={'a':'a1,a2,a3,a4','b':'b1,b2,b3,b4','c':'c1,c2,c3,c4'}
d2={'a1':'a11,a12,a13,a14,a15','a2':'a21,a22,a23,a24,a25', 'b1':'b11,b12,b13,b14,b15','b2':'b21,b22,b23,b24,b25'}
dict1 = {k: {i: d2[i] for i in v.split(",") if i in d2} for k, v in d.items()})
print(dict1)
Output in this case
{'a': {'a1': 'a11,a12,a13,a14,a15', 'a2': 'a21,a22,a23,a24,a25'}, 'b': {'b1': 'b11,b12,b13,b14,b15', 'b2': 'b21,b22,b23,b24,b25'}, 'c': {}}
So if there will be values in d2 about the the c's they will be in the dict1 results as well.
Maybe you can try with:
dict1={}
for i in d:
q=d[i].split(",")
for j in q:
if not dict1.get(i, None):
dict1[i] = {}
if j in d2:
dict1[i][j] = d2[j]

How to merge two dicts and combine common keys?

I would like to know how if there exists any python function to merge two dictionary and combine all values that have a common key.
I have found function to append two dict, to merge two dict but not to combine its values.
Example:
D1 = [{k1: v01}, {k3: v03}, {k4: v04},}],
D2 = [{k1: v11}, {k2: v12}, {k4: v14},}],
this should be the expected result:
D3 = [
{k1: [v01, v11]},
{k2: [ v12]},
{K3: [v03 ]},
{k4: [v04, v14]},
]
There is no built-in function for this but you can use a defaultdict for this:
from collections import defaultdict
d = defaultdict(list)
for other in [d1, d1]:
for k, v in other.items():
d[k].append(v)
A solution, without importing anything:
# First initialize data, done correctly here.
D1 = [{'k1': 'v01'}, {'k3': 'v03'}, {'k4': 'v04'}]
D2 = [{'k1': 'v11'}, {'k2': 'v12'}, {'k4': 'v14'}]
# Get all unique keys
keys = {k for d in [*D1, *D2] for k in d}
# Initialize an empty dict
D3 = {x:[] for x in keys}
# sort to maintain order
D3 = dict(sorted(D3.items()))
#Iterate and extend
for x in [*D1, *D2]:
for k,v in x.items():
D3[k].append(v)
# NOTE: I do not recommend you convert a dictionary into a list of records.
# Nonetheless, here is how it would be done.
# To convert to a list
D3_list = [{k:v} for k,v in D3.items()]
print(D3_list)
# [{'k1': ['v01', 'v11']},
# {'k2': ['v12']},
# {'k3': ['v03']},
# {'k4': ['v04', 'v14']}]
If you meant to use actual dicts, instead of lists of dicts, this is easier.
D1 = dict(k1=1, k3=3, k4=4)
D2 = dict(k1=11, k2=12, k4=14)
There isn't a simple built-in function to do this, but the setdefault method is close.
It tries to get the given key, but creates it if it doesn't exist.
D3 = {}
for k, v in D1.items() | D2.items():
D3.setdefault(k, set()).add(v)
And the result.
{'k4': {4, 14}, 'k1': {1, 11}, 'k3': {3}, 'k2': {12}}
This all assumes the order doesn't matter, just combining sets.
A more generic way to merge dicts together may look like this.
(To answer a similar SO question)
def merge(combiner, dicts):
new_dict = {}
for d in dicts:
for k, v in d.items():
if k in new_dict:
new_dict[k] = combiner(new_dict[k], v)
else:
new_dict[k] = v
return new_dict
x = {'a': 'A', 'b': 'B'}
y = {'b': 'B', 'c': 'C'}
z = {'a': 'A', 'd': 'D'}
merge_dicts(combiner= lambda x, y: f'{x} AND {y}', dicts=(x,y,z))
# {'a': 'A AND A', 'b': 'B AND B', 'c': 'C', 'd': 'D'}

How to remove dictionary key with known value?

Assume python dict:
mydict = {'a': 100, 'b': 200, 'c': 300}
I know one of the values:
value = 200
How to remove the 'b': 200 pair from the dict? I need this:
mydict = {'a': 100, 'c': 300}
Use a dictionary comprehension. Note that (as jonrsharpe has stated) this will create a new dictionary which excludes the key:value pair that you want to remove. If you want to delete it from your original dictionary then please see his answer.
>>> d = {'a': 100, 'b': 200, 'c': 300}
>>> val = 200
# Use d.items() for Python 2.x and d.iteritems() for Python 3.x
>>> d2 = {k:v for k,v in d.items() if v != val}
>>> d2
{'a': 100, 'c': 300}
It sounds like you want:
for key, val in list(mydict.items()):
if val == value:
del mydict[key]
break # unless you want to remove multiple occurences
You'll need to loop over every items(), either with dict comprehension:
new_dict = {k:v for k,v in my_dict.items() if predicate(value)}
Or modifying the existing dictionary:
for k,v in my_dict.items():
if not predicate(v):
del my_dict[k]
The simplest i found:
for key in [k for k,v in mydict.items() if v==200]:
del mydict[key]

remove the keys which has blank values

how to remove keys in a dict which do not have any value. I have a dict as :
d = {'CB': '', 'CA': [-7.5269999504089355, -2.2330000400543213, 6.748000144958496], 'C': [-8.081000328063965, -3.619999885559082, 6.406000137329102], 'N': [-6.626999855041504, -2.318000078201294, 7.9029998779296875], 'H':''}
I want to remove keys which values are blank. I need output as :
d = {'CA': [-7.5269999504089355, -2.2330000400543213, 6.748000144958496], 'C': [-8.081000328063965, -3.619999885559082, 6.406000137329102], 'N': [-6.626999855041504, -2.318000078201294, 7.9029998779296875]}
how to do this?
Use a dict-comprehension:
>>> {k:v for k, v in d.items() if v != ''}
{'N': [-6.626999855041504, -2.318000078201294, 7.9029998779296875], 'CA': [-7.5269999504089355, -2.2330000400543213, 6.748000144958496], 'C': [-8.081000328063965, -3.619999885559082, 6.406000137329102]}
If by empty you meant any falsy value then use just if v.
If you want to modify the original dict itself(this will affect all the references to the dict object):
for k, v in d.items():
if not v: del d[k]
>> {key:value for key, value in d.items() if value}
If you really need to do this in one-line:
for k in [k for k,v in d.iteritems() if not v]: del d[k]
This is ugly. It makes a list of all of the keys in d that have a "blank" value and then iterates over this list removing the keys from d (to avoid the unsafe removal of items from dictionary during iteration).
I'd suggest that three lines would be more readable:
blanks = [k for k,v in d.iteritems() if not v]
for k in blanks:
del d[k]
If making a fresh dict is acceptable, use a dict comprehension:
d2 = {k:v for k,v in d.iteritems() if not v}

How I can get rid of None values in dictionary?

Something like:
for (a,b) in kwargs.iteritems():
if not b : del kwargs[a]
This code raise exception because changing of dictionary when iterating.
I discover only non pretty solution with another dictionary:
res ={}
res.update((a,b) for a,b in kwargs.iteritems() if b is not None)
Thanks
Another way to write it is
res = dict((k,v) for k,v in kwargs.iteritems() if v is not None)
In Python3, this becomes
res = {k:v for k,v in kwargs.items() if v is not None}
You can also use filter:
d = dict(a = 1, b = None, c = 3)
filtered = dict(filter(lambda item: item[1] is not None, d.items()))
print(filtered)
{'a': 1, 'c': 3}
d = {'a': None, 'b': 'myname', 'c': 122}
print dict(filter(lambda x:x[1], d.items()))
{'b': 'myname', 'c': 122}
I like the variation of your second method:
res = dict((a, b) for (a, b) in kwargs.iteritems() if b is not None)
it's Pythonic and I don't think that ugly. A variation of your first is:
for (a, b) in list(kwargs.iteritems()):
if b is None:
del kwargs[a]
If you need to handle nested dicts, then you can leverage a simple recursive approach:
# Python 2
from collections import Mapping
def filter_none(d):
if isinstance(d, Mapping):
return dict((k, filter_none(v)) for k, v, in d.iteritems() if v is not None)
else:
return d
# Python 3
from collections.abc import Mapping
def filter_none(d):
if isinstance(d, Mapping):
return {k: filter_none(v) for k, v in d.items() if v is not None}
else:
return d
To anybody who may interests, here's another way to get rid of None value. Instead of deleting the key, I change the value of None with a placeholder for the same key.
One use case is applying with Spark RDD.map onto null valued JSON.
def filter_null(data, placeholder="[spark]nonexists"):
# Replace all `None` in the dict to the value of `placeholder`
return dict((k, filter_null(v, placeholder) if isinstance(v, dict) else v if v
is not None else placeholder) for k, v in data.iteritems())
Sample output:
>>> filter_null({'a':None,'b':"nul", "c": {'a':None,'b':"nul"}})
{'a': '[spark]nonexists', 'c': {'a': '[spark]nonexists', 'b': 'nul'}, 'b': 'nul'}
For python3, change the iteritems() to items().
The recursive approach to also filter nested lists of dicts in the dictionary:
def filter_none(d):
if isinstance(d, dict):
return {k: filter_none(v) for k, v in d.items() if v is not None}
elif isinstance(d, list):
return [filter_none(v) for v in d]
else:
return d
Sample output:
data = {'a': 'b', 'c': None, 'd':{'e': 'f', 'h': None, 'i':[{'j': 'k', 'l': None}]}}
print(filter_none(data))
>>> {'a': 'b', 'd': {'e': 'f', 'i': [{'j': 'k'}]}}

Categories