How to append a value to a not yet existing key? - python

I have a dictionary like this:
dct = {'one': 'value',
'two': ['value1','value2','value1'],
'three':['otherValue1','otherValue2','otherValue1'],
'dontCareAboutThisKey':'debug'}
I need to remove duplicate values from the lists. I wrote a function to do this:
no_dups = {}
for keys in dct:
if isinstance(dct[keys], list) and keys != 'dontCareAboutThisKey':
for value in dct[keys]:
if value not in no_dups.values():
no_dups[keys].append(value)
else:
no_dups[keys] = dct[keys]
I'm checking if value of the current key is a list. If no, it just 'copy' key to no_dups dictionary. If it is a list and not a key that I don't care about (there are no duplicates for sure) - it should check if current value already exists in no_dups.values() and append it to current key. Problem is that I'm getting an error:
KeyError: 'two:'
I know it's because I'm trying to add a value to non existing key but I have no idea how to deal with this and make it work.

I think the best way to deal with adding the key and appending at the same time is with dicts' setdefault() method:
no_dups.setdefault(keys,[]).append(value)
But rather than that, you can do this in a more neat way like this:
#remove duplicates
no_dups = {k:list(set(v)) if isinstance(v, list) and k != 'dontCareAboutThisKey' else v
for k,v in dct.items()} # or dct.iteritems() if using python2.x
That hack will, for key value combinations that pass the if test, convert the list into a set (removing duplicates) and then in a list again. For other key value combinations it will leave it intact.

dct = {'one': 'value',
'two': ['value1','value2','value1'],
'three':['otherValue1','otherValue2','otherValue1'],
'dontCareAboutThisKey':'debug'}
set(dct) returns a set, which is a list without duplicates:
for key, value in dct.items():
if not isinstance(value, basestring):
dct[key] = set(value)
If you need a new dictionary you could do:
new_dct = {}
for key, value in dct.items():
if not isinstance(value, basestring):
new_dct[key] = set(value)
else:
new_dct[key] = value

If You want to remove duplicates, just change You list to set, with set() function:
https://docs.python.org/2/tutorial/datastructures.html#sets
It automatically gives You unique set, then You can always change it back to list.

Related

Comparing the strings in key and value of the same dictionary

I am looking to solve a problem to compare the string of the key and value of the same dictionary.
To return a dictionary of all key and values where the value contains the key name as a substring.
a = {"ant":"antler", "bi":"bicycle", "cat":"animal"}
the code needs to return the result:
b = {"ant":"antler", "bi":"bi cycle"}
You can iterate through the dictionary and unpack the key and the value at the same time this way:
b = {}
for key, value in a.items():
if value in key:
b[value] = key
This will generate your wanted solution. It does that by unpacking both the key and the value and checking if they match afterward.
You can also shorten that code by using a dictionary comprehension:
b = {key:value for key, value in a.items() if key in value}
This short line does the exact same thing as the code before. It even uses the same functionalities with only one addition - a dictionary comprehension. That allows you to put all that code in one simple line and declare the dictionary on the go.
answer = {k:v for k,v in a.items() if k in v}
Notes:
to iterate over key: value pair we use dict.items();
to check if a string is inside some other string we use in operator;
to filter items we use if-clause in the dictionary comprehension.
See also:
about dictionary comprehensions
about operators in and not in

How to Get a Key value from a dictionary whose values are lists?

I have a dictionary where each key has several lists of data as its values like this
myDict = {'data1' : ['data_d','dataD']['data_e','dataE']['data_f','dataF']}
I want to be able to input one of the values in the list and then be given the key. This is so I can get the other value in the list now that I have the key.
I've tried
dataKey = (list(myDict.keys())[list(myDict.values()).index(dataD)])
but that didn't work
I've also tried
for k, v in myDict.items():
if 'dataD' in v:
print k
but that didn't work as well.
Side question, in the questions that I've looked through, I see people using the variable k and v a lot even without the OP mentioning them, so I am wondering if k and v are already set variable in dictionaries?
Your second attempt was almost right, but a nested for loop is needed to traverse the list-of-lists:
myDict = {'data1' : [['data_d','dataD'], ['data_e','dataE'], ['data_f','dataF']]}
for key, value in myDict.items():
for sublist in value:
if 'dataD' in sublist:
print(key) # -> data1
Using variables named k, and v with dictionaries is purely optional and aren't special properties—other than being very short abbreviations for "key" and "value".
Note that if only one match is ever expected to occur, the code could be made more efficient by stopping the search after one is found. Here's one way of doing that:
target = 'dataD'
try:
for key, value in myDict.items():
for sublist in value:
if target in sublist:
print(key) # -> data1
raise StopIteration # found, so quit searching
except StopIteration:
pass # found
else:
print('{} not found'.format(target))
if they are all going to be lists then you can do something like this (if i am understanding correctly)
myDict = {
'data1': [['data_d','dataD'], ['data_e','dataE'], ['data_f','dataF']],
}
def find(dic, item):
for k, v in dic.items():
for ls in v:
if item in ls:
return k
return False
print(find(myDict, "data_d"))
# OUT [data1]

Strip nested dict of non zero values

I'm trying to strip a nested dict (only 1 level deep eg: some_dict = {'a':{}, b:{}} all all non-zero and none values.
However I'm not sure who to reassemble the dict properly, the below gives me a key error.
def strip_nested_dict(self, some_dict):
new_dict = {}
for sub_dict_key, sub_dict in some_dict.items():
for key, value in sub_dict.items():
if value:
new_dict[sub_dict_key][key] = value
return new_dict
You need to create the nested dictionary before accessing it:
for sub_dict_key, sub_dict in some_dict.items():
new_dict[sub_dict_key] = {} # Add this line
for key, value in sub_dict.items():
# no changes
(In order for new_dict[sub_dict_key][key] to work, new_dict must be a dictionary, & new_dict[sub_dict_key] also has to be a dictionary.)
This worked. Shame you can't just assign a nested value without having to create an empty for for each key first.
def strip_nested_dict(self, some_dict):
new_dict = {}
for sub_dict_key, sub_dict in some_dict.items():
new_dict[sub_dict_key] = {}
for key, value in sub_dict.items():
if value:
new_dict[sub_dict_key][key] = value
return new_dict

Adding nonzero items from a dictionary to another dictionary

I have a set of reactions (keys) with values (0.0 or 100) stored in mydict.
Now I want to place non zero values in a new dictionary (nonzerodict).
def nonzero(cmod):
mydict = cmod.getReactionValues()
nonzerodict = {}
for key in mydict:
if mydict.values() != float(0):
nonzerodict[nz] = mydict.values
print nz
Unfortunately this is not working.
My questions:
Am I iterating over a dictionary correctly?
Am I adding items to the new dictionary correctly?
You are testing if the list of values is not equal to float(0). Test each value instead, using the key to retrieve it:
if mydict[key] != 0:
nonzerodict[key] = mydict[key]
You are iterating over the keys correctly, but you could also iterate over the key-value pairs:
for key, value in mydict.iteritems():
if value != 0:
nonzerodict[key] = value
Note that with floating point values, chances are you'll have very small values, close to zero, that you may want to filter out too. If so, test if the value is close to zero instead:
if abs(value) > 1e-9:
You can do the whole thing in a single dictionary expression:
def nonzero(cmod):
return {k: v for k, v in cmod.getReactionValues().iteritems() if abs(v) > 1e-9}
Its simple and you can it by below way -
>>> d = {'a':4,'b':2, 'c':0}
>>> dict((k,v) for k,v in d.iteritems() if v!=0)
{'a': 4, 'b': 2}
>>>
Replace if condition in you code with:
if mydict[key]:
nonzerodict[key] = mydict[key]
Your solution can be further simplified as:
def nonzero(cmod):
mydict = cmod.getReactionValues()
nonzerodict = {key: value for key, value in mydict.iteritems() if value}

index python dictionary by value [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Inverse dictionary lookup - Python
Is there a built in way to index a dictionary by value in Python.
e.g. something like:
dict = {'fruit':'apple','colour':'blue','meat':'beef'}
print key where dict[key] == 'apple'
or:
dict = {'fruit':['apple', 'banana'], 'colour':'blue'}
print key where 'apple' in dict[key]
or do I have to manually loop it?
You could use a list comprehension:
my_dict = {'fruit':'apple','colour':'blue','meat':'beef'}
print [key for key, value in my_dict.items() if value == 'apple']
The code above is doing almost exactly what said you want:
print key where dict[key] == 'apple'
The list comprehension is going through all the key, value pairs given by your dictionary's items method, and making a new list of all the keys where the value is 'apple'.
As Niklas pointed out, this does not work when your values could potentially be lists. You have to be careful about just using in in this case since 'apple' in 'pineapple' == True. So, sticking with a list comprehension approach requires some type checking. So, you could use a helper function like:
def equals_or_in(target, value):
"""Returns True if the target string equals the value string or,
is in the value (if the value is not a string).
"""
if isinstance(target, str):
return target == value
else:
return target in value
Then, the list comprehension below would work:
my_dict = {'fruit':['apple', 'banana'], 'colour':'blue'}
print [key for key, value in my_dict.items() if equals_or_in('apple', value)]
You'll have to manually loop it, but if you'll need the lookup repeatedly this is a handy trick:
d1 = {'fruit':'apple','colour':'blue','meat':'beef'}
d1_rev = dict((v, k) for k, v in d1.items())
You can then use the reverse dictionary like this:
>>> d1_rev['blue']
'colour'
>>> d1_rev['beef']
'meat'
Your requirements are more complex than you realize:
You need to handle both list values and plain values
You don't actually need to get back a key, but a list of keys
You could solve this in two steps:
normalize the dict so that every value is a list (every plain value becomes a single-element)
build a reverse dictionary
The following functions will solve this:
from collections import defaultdict
def normalize(d):
return { k:(v if isinstance(v, list) else [v]) for k,v in d.items() }
def build_reverse_dict(d):
res = defaultdict(list)
for k,values in normalize(d).items():
for x in values:
res[x].append(k)
return dict(res)
To be used like this:
>>> build_reverse_dict({'fruit':'apple','colour':'blue','meat':'beef'})
{'blue': ['colour'], 'apple': ['fruit'], 'beef': ['meat']}
>>> build_reverse_dict({'fruit':['apple', 'banana'], 'colour':'blue'})
{'blue': ['colour'], 'apple': ['fruit'], 'banana': ['fruit']}
>>> build_reverse_dict({'a':'duplicate', 'b':['duplicate']})
{'duplicate': ['a', 'b']}
So you just build up the reverse dictionary once and then lookup by value and get back a list of keys.

Categories

Resources