I had a python dict like this:
{'1' : {'1': {'A' : 34, 'B' : 23, 'C' : nan, 'D': inf, ...} ....} ....}
For each "letter" key I had to calculate something, but I obtained values like inf or nan and I need to remove them. How could I do that?
My first tried was to "cut" such values, i.e., to return just values between 0 and 1000 but when I did this, I got a dict with empty values:
{'1' : {'1': {'A' : 34, 'B' : 23, 'C' : {}, 'D': {}, ...} ....} ....}
perhaps there is a better solution, please help!!!!
This is part of my code, (Q and L are other dict that have the info that I need to calculate):
for e in L.keys():
dR[e] = {}
for i in L[e].keys():
dR[e][i] = {}
for l, ivalue in L[e][i].iteritems():
for j in Q[e].keys():
dR[e][i][j] = {}
for q, jvalue in Q[e][j].iteritems():
deltaR = DeltaR(ivalue, jvalue) #this is a function that I create previously
if (0 < deltaR < 100):
dR[e][i][j] = deltaR
You should be able to use the del statement to delete the dictionary item. For example:
del dct['1']['1']['C']
I'm taking a shot in the dark here, but you can probably do it in a couple of different ways. One method would be to calculate the value and then decide whether or not you actually want to keep it before sticking it into the dictionary.
d = {}
for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
# I don't actually know how you're calculating values
# and it kind of doesn't matter
value = calculate(letter)
if value in (inf, nan):
continue
d[letter] = value
I'm simplifying the dictionary to only pay attention to the part of your data that actually uses letters as keys since you haven't really given any context. That being said, I'd probably go with the first suggestion unless there's a reason not to.
for e in L.keys():
dR[e] = {}
for i in L[e].keys():
dR[e][i] = {}
for l, ivalue in L[e][i].iteritems():
for j in Q[e].keys():
#dR[e][i][j] = {} # What's up with this? If you don't want an empty dict,
# just don't create one.
for q, jvalue in Q[e][j].iteritems():
deltaR = DeltaR(ivalue, jvalue) #this is a function that I create previously
if (0 < deltaR < 100):
dR[e][i][j] = deltaR
if dR[e][i][j] in (nan, inf):
del dR[e][i][j]
Related
I'm a Python Newb and trying to create a dictionary with ordered values.
Since dict.fromkeys only allows me to copy the same value for each key, I've set all values to 0 and tried something like this:
def Ord_Values_in_Dic(D):
c = 0
for value in D.values():
c += 1
value += c
return D
My output only changes the first value of the dictionary to 1 though, instead I'd want the second value to also change to 2, the third value to change to 3 and so on...
I don't get if the loop isn't iterating correctly through the dictionary or there's something else wrong.
Since dict.fromkeys only allows me to copy the same value for each key
then it is not right tool for you task. You might use zip to prepare dict from 2 iterables - one for keys, one for values, consider following simple example
keys = ["x","y","z"]
d = dict(zip(keys,range(3)))
print(d) # {'x': 0, 'y': 1, 'z': 2}
range with single arguments gives subsequent numbers from 0 (inclusive) to given value (exclusive), so in above example: 0,1,2
Got it!
import numpy as np
a = np.linspace(0,100,100)
b = np.sin(a)
c = np.cos(a)
idx = list(range(1,101))
X = dict(zip(b, idx))
Y = dict(zip(c, idx))
This solved it!
Thank you :)
I was running this code through python tutor, and was just confused as to how the keys and values get switched around. I also was confused as to what value myDict[d[key]] would correspond to as I'm not sure what the d in [d[key]] actually does.
def dict_invert(d):
'''
d: dict
Returns an inverted dictionary according to the instructions above
'''
myDict = {}
for key in d.keys():
if d[key] in myDict:
myDict[d[key]].append(key)
else:
myDict[d[key]] = [key]
for val in myDict.values():
val.sort()
return myDict
print(dict_invert({8: 6, 2: 6, 4: 6, 6: 6}))
In your function d is the dictionary being passed in. Your code is creating a new dictionary, mapping the other direction (from the original dictionary's values to its keys). Since there may not be a one to one mapping (since values can be repeated in a dictionary), the new mapping actually goes from value to a list of keys.
When the code loops over the keys in d, it then uses d[key] to look up the corresponding value. As I commented above, this is not really the most efficient way to go about this. Instead of getting the key first and indexing to get the value, you can instead iterate over the items() of the dictionary and get key, value 2-tuples in the loop.
Here's how I'd rewrite the function, in what I think is a more clear fashion (as well as perhaps a little bit more efficient):
def dict_invert(d):
myDict = {}
for key, value in d.items(): # Get both key and value in the iteration.
if value in myDict: # That change makes these later lines more clear,
myDict[value].append(key) # as they can use value instead of d[key].
else:
myDict[value] = [key] # here too
for val in myDict.values():
val.sort()
return myDict
The function you are showing inverts a dictionary d. A dictionary is a collection of unique keys that map to values which are not necessarily unique. That means that when you swap keys and values, you may get multiple keys that have the same value. Your function handles this by adding keys in the input to a list in the inverse, instead of storing them directly as values. This avoids any possibility of conflict.
Let's look at a sample conceptually first before digging in. Let's say you have
d = {
'a': 1,
'b': 1,
'c': 2
}
When you invert that, you will have the keys 1 and 2. Key 1 will have two values: 'a' and 'b'. Key 2 will only have one value: 'c'. I used different types for the keys and values so you can tell immediately when you're looking at the input vs the output. The output should look like this:
myDict = {
1: ['a', 'b'],
2: ['c']
}
Now let's look at the code. First you initialize an empty output:
myDict = {}
Then you step through every key in the input d. Remember that these keys will become the values of the output:
for key in d.keys():
The value in d for key is d[key]. You need to check if that's a key in myDict since values become keys in the inverse:
if d[key] in myDict:
If the input's value is already a key in myDict, then it maps to a list of keys from d, and you need to append another one to the list. Specifically, d[key] represents the value in d for the key key. This value becomes a key in myDict, which is why it's being indexed like that:
myDict[d[key]].append(key)
Otherwise, create a new list with the single inverse recorded in it:
else:
myDict[d[key]] = [key]
The final step is to sort the values of the inverse. This is not necessarily a good idea. The values were keys in the input, so they are guaranteed to be hashable, but not necessarily comparable to each other:
for val in myDict.values():
val.sort()
The following should raise an error in Python 3:
dict_invert({(1, 2): 'a', 3: 'b'})
myDict[d[key]] takes value of d[key] and uses it as a key in myDict, for example
d = {'a': 'alpha', 'b': 'beta'}
D = {'alpha': 1, 'beta': 2}
D[d['a']] = 3
D[d['b']] = 4
now when contents of d and D should be as following
d = {'a': 'alpha', 'b': 'beta'}
D = {'alpha': 3, 'beta': 4}
d is the dictionary you are passing into the function
def dict_invert(d)
When you create
myDict[d[key]] = d
Its meaning is
myDict[value of d] = key of d
Resulting in
myDict = {'value of d': 'key of d'}
Maybe the dict is not intended to be used in this way, but I need to add more than one value to the same key. My intension is to use a kind of transitory property. If my dict is A:B and B:C, than I want to have the dict A:[B,C].
Let's make an example in order to explain better what I'd like to do:
numDict={'60':['4869'], '4869':['629'], '13':['2']}
I want it to return:
{'60':['4869','629'], '13':['2']}
For just two elements, it is possible to use something like this:
result={}
for key in numDict.keys():
if [key] in numDict.values():
result[list(numDict.keys())[list(numDict.values()).index([key])]]=[key]+numDict[key]
But what about if I have more elements? For example:
numDict={'60':['4869'], '4869':['629'], '13':['2'], '629':['427'}
What can I do in order to get returned {'60':[4869,629,427'], '13':['2']}?
def unchain(d):
#assemble a collection of keys that are not also values. These will be the keys of the final dict.
top_level_keys = set(d.keys()) - set(d.values())
result = {}
for k in top_level_keys:
chain = []
#follow the reference chain as far as necessary.
value = d[k]
while True:
if value in chain: raise Exception("Referential loop detected: {} encountered twice".format(value))
chain.append(value)
if value not in d: break
value = d[value]
result[k] = chain
return result
numDict={'60':'4869', '4869':'629', '13':'2', '629':'427'}
print(unchain(numDict))
Result:
{'60': ['4869', '629', '427'], '13': ['2']}
You might notice that I changed the layout of numDict since it's easier to process if the values aren't one-element lists. But if you're dead set on keeping it that way, you can just add d = {k:v[0] for k,v in d.items()} to the top of unchain, to convert from one to the other.
You can build your own structure, consisting of a reverse mapping of (values, key), and a dictionary of (key, [values]). Adding a key, value pair consists of following a chain of existing entries via the reverse mapping, until it finds the correct location; in case it does not exist, it introduces a new key entry:
class Groupir:
def __init__(self):
self.mapping = {}
self.reverse_mapping = {}
def add_key_value(self, k, v):
self.reverse_mapping[v] = k
val = v
key = k
while True:
try:
self.reverse_mapping[val]
key = val
val = self.reverse_mapping[val]
except KeyError:
try:
self.mapping[val].append(v)
except KeyError:
self.mapping[val] = [v]
break
with this test client:
groupir = Groupir()
groupir.add_key_value(60, 4869)
print(groupir.mapping)
groupir.add_key_value(4869, 629)
print(groupir.mapping)
groupir.add_key_value(13, 2)
print(groupir.mapping)
groupir.add_key_value(629, 427)
print(groupir.mapping)
outputs:
{60: [4869]}
{60: [4869, 629]}
{60: [4869, 629], 13: [2]}
{60: [4869, 629, 427], 13: [2]}
Restrictions:
Cycles as mentioned in comments.
Non unique keys
Non unique values
Probably some corner cases to take care of.
I have written a code for it. See if it helps.
What I have done is to go on diving in till i can go (hope you understand this statement) and mark them as visited as they will no longer be required. At the end I filter out the root keys.
numDict={'60':['4869'], '4869':['629'], '13':['2'], '629':['427']}
l = list(numDict) # list of keys
l1 = {i:-1 for i in numDict} # to track visited keys (initialized to -1 initially)
for i in numDict:
# if key is root and diving in is possible
if l1[i] == -1 and numDict[i][0] in l:
t = numDict[i][0]
while(t in l): # dive deeper and deeper
numDict[i].extend(numDict[t]) # update the value of key
l1[t] = 1 # mark as visited
t = numDict[t][0]
# filter the root keys
answer = {i:numDict[i] for i in numDict if l1[i] == -1}
print(answer)
Output:
{'60': ['4869', '629', '427'], '13': ['2']}
I'm taking two lists of tuples, doing some calculations and creating a dictionary, or at least trying to, so that I can find the character with the largest percentage.
dict_original = dict(original_list)
for c, p in new_list:
if c in dict_original and dict_original[c] < p:
diff = p - dict_original[c]
output = {c:round(diff,3)}
print output
The output i'm getting is something like this:
{'o': 0.026}
{'x': 0.046}
{'t': 0.037}
{'/': 0.038}
{'p': 0.037}
{'s': 0.038}
All I want is the character with the largest percentage; 'x', in this case. I've been unsuccessful using max so far.
I know, my output seems to be a bunch of dictionaries, that's why i'm asking for some help here.
Thanks!
Without seeing your data it is hard to give you proper guidance.
You are not creating a new dictionary of all the results just a dict per result which is being discarded. You can create a complete dictionary using a dict comprehension, e.g. this is equivalent to your for loop:
do = dict_original
output = {c: round(p-do[c], 3) for c, p in new_list if do.get(c, float('inf')) < p}
To get the maximum value from this dict then as pointed out by #batman:
max(output, key=output.get)
Would return 'x'
You can pass max a key argument:
bar = max(foo, key=foo.get)
That will give you the key with the largest value.
Suppose I have this dictionary:
x = {'a':2, 'b':5, 'g':7, 'a':3, 'h':8}`
And this input string:
y = 'agb'
I want to delete the keys of x that appear in y, such as, if my input is as above, output should be:
{'h':8, 'a':3}
My current code is here:
def x_remove(x,word):
x1 = x.copy() # copy the input dict
for i in word: # iterate all the letters in str
if i in x1.keys():
del x1[i]
return x1
But when the code runs, it removes all existing key similar as letters in word. But i want though there is many keys similar as letter in word , it only delete one key not every
wheres my wrong, i got that maybe but Just explain me how can i do that without using del function
You're close, but try this instead:
def x_remove(input_dict, word):
output_dict = input_dict.copy()
for letter in word:
if letter in output_dict:
del output_dict[letter]
return output_dict
For example:
In [10]: x_remove({'a': 1, 'b': 2, 'c':3}, 'ac')
Out[10]: {'b': 2}
One problem was your indentation. Indentation matters in Python, and is used the way { and } and ; are in other languages. Another is the way you were checking to see if each letter was in the list; you want if letter in output_dict since in on a dict() searches keys.
It's also easier to see what's going on when you use descriptive variable names.
We can also skip the del entirely and make this more Pythonic, using a dict comprehension:
def x_remove(input_dict, word):
return {key: value for key, value in input_dict if key not in word}
This will still implicitly create a shallow copy of the list (without the removed elements) and return it. This will be more performant as well.
As stated in the comments, all keys in dictionaries are unique. There can only ever be one key named 'a' or b.
Dictionary must have unique keys. You may use list of tuples for your data instead.
x = [('a',2), ('b',5), ('g',7), ('a',3), ('h',8)]
Following code then deletes the desired entries:
for letter in y:
idx = 0
for item in x.copy():
if item[0] == letter:
del x[idx]
break
idx += 1
Result:
>>> x
[('a', 3), ('h', 8)]
You can also implement like
def remove_(x,y)
for i in y:
try:
del x[i]
except:
pass
return x
Inputs x = {'a': 1, 'b': 2, 'c':3} and y = 'ac'.
Output
{'b': 2}