find the key with longest path from the dictionary - python

find the key with longest path from the dictionary. The key value pair will be integers. consider the following dictionary d={2:1,3:2,4:5,1:4}
here the first key is 2 and its value is 1. so you need to find the value of key 1. this method has to follow until the value is not present in the dictionary as a key or the value become the key where we start to traverse the dictionary
i tried like this :
d = {2: 1, 3: 2, 4: 5, 1: 4}
k = 0
count = 0
def find(k):
m = d[k]
return m
for i in d.keys():
k = d[i]
find(k)
count = count + 1
print(count)
my aim pass the each to function and return

If I'm right, this is the functionality you require:
d = {2:1, 3:2, 4:5, 1:4}
so if
key = 2, value = 1;
key = 1, value = 4;
key = 4, value = 5;
key = 5 --> No value so stop here
Thus to find the key with the longest path:
d={2:1,3:2,4:5,1:4}
c1=0
ans_key = -1
for i in d.keys():
k=i
c=0
while(k in d.keys()):
k = d[k]
c+=1
if(c1<c):
c1=c
ans_key=i
print("The Key with the longest path is",ans_key)
This will return the output:
The Key with the longest path is 3
Hope this helps!

Related

how to remove dictionary element by outlier values Python

Suppose my dictionary contains > 100 elements and one or two elements have values different than other values; most values are the same (12 in the below example). How can I remove these a few elements?
Diction = {1:12,2:12,3:23,4:12,5:12,6:12,7:12,8:2}
I want a dictionary object:
Diction = {1:12,2:12,4:12,5:12,6:12,7:12}
It may be a bit slow because of the looping (especially as the size of the dictionary gets very large) and have to use numpy, but this will work
import numpy as np
Diction = {1:12,2:12,3:23,4:12,5:12,6:12,7:12,8:2}
dict_list = []
for x in Diction:
dict_list.append(Diction[x])
dict_array = np.array(dict_list)
unique, counts = np.unique(dict_array, return_counts=True)
most_common = unique[np.argmax(counts)]
new_Diction = {}
for x in Diction:
if Diction[x] == most_common:
new_Diction[x] = most_common
print(new_Diction)
Output
{1: 12, 2: 12, 4: 12, 5: 12, 6: 12, 7: 12}
d = {1:12,2:12,3:23,4:12,5:12,6:12,7:12,8:2}
new_d = {}
unique_values = []
unique_count = []
most_occurence = 0
# Find unique values
for k, v in d.items():
if v not in unique_values:
unique_values.append(v)
# Count their occurrences
def count(dict, unique_value):
count = 0
for k, v in d.items():
if v == unique_value:
count +=1
return count
for value in unique_values:
occurrences = count(d, value)
unique_count.append( (value, occurrences) )
# Find which value has most occurences
for occurrence in unique_count:
if occurrence[1] > most_occurence:
most_occurence = occurrence[0]
# Create new dict with keys of most occurred value
for k, v in d.items():
if v == most_occurence:
new_d[k] = v
print(new_d)
Nothing fancy, but direct to the point. There should be many ways to optimize this.
Output: {1: 12, 2: 12, 4: 12, 5: 12, 6: 12, 7: 12}

Count the occurance of same value for the key in dictionary python

I have a multiple dicts in the list. I want to count the number of occurances of the certain value from the list of dicts.
Here's the list of dict:
a = [{"a":"data1","b":"Nill","c":"data3","d":"Nill"},{"a":"dat1","b":"dat2","c":"dat3","d":"Nill"},{"a":"sa1","b":"sa2","c":"sa3","d":"Nill"}]
In here, i want to count the occurance of Nill in the Key. How to make it possible.
Here's the code i tried:
from collections import Counter
a = [{"a":"data1","b":"Nill","c":"data3","d":"Nill"},{"a":"dat1","b":"dat2","c":"dat3","d":"Nill"},{"a":"sa1","b":"sa2","c":"sa3","d":"Nill"}]
s = 0
for i in a:
d = (a[s])
#print(d)
q = 0
for z in d:
print(z)
z1=d[z]
#print(z)
if z1 == "Nill":
q = q+1
co = {z:q}
print(co)
Expected Output:
The count of Nill values in the list of dict
{a:0,b:1,c:0,d:3}
Try this :-
a = [{"a":"data1","b":"Nill","c":"data3","d":"Nill"},{"a":"dat1","b":"dat2","c":"dat3","d":"Nill"},{"a":"sa1","b":"sa2","c":"sa3","d":"Nill"}]
result_dict = {'a' : 0, 'b' : 0,'c' :0, 'd' : 0}
for i in a:
for key, value in i.items():
if value =="Nill":
result_dict[key] +=1
print(result_dict)
You can use the Counter directly by counting the boolean expression with something like this that takes advantage of the fact the the counter will count True as 1.
a = [{"a":"data1","b":"Nill","c":"data3","d":"Nill"},{"a":"dat1","b":"dat2","c":"dat3","d":"Nill"},{"a":"sa1","b":"sa2","c":"sa3","d":"Nill"}]
c = Counter()
for d in a:
c.update({k: v == 'Nill' for k, v in d.items()})
# c => Counter({'a': 0, 'b': 1, 'c': 0, 'd': 3})
EDIT:
To match the output required:
import pandas as pd
df = pd.DataFrame(a)
occ = {k: list(v.values()).count('Nill') for k,v in df.to_dict().items()}
Like this?
a = [{"a":"data1","b":"Nill","c":"data3","d":"Nill"},{"a":"dat1","b":"dat2","c":"dat3","d":"Nill"},{"a":"sa1","b":"sa2","c":"sa3","d":"Nill"}]
result = {}
for sub_list in a: # loop through the list
for key, val in sub_list.items(): # loop through the dictionary
result[key] = result.get(key, 0) # if key not in dictionary, add it
if val == 'Nill': # if finding 'Nill', increment that value
result[key] += 1
for key, val in result.items(): # show result
print(key, val)
Try this:
from collections import defaultdict
c = defaultdict(int, {i:0 for i in a[0].keys()})
for i in a:
for k,v in i.items():
if v=='Nill':
c[k] += 1
dict(c) will be your desired output.
{'a': 0, 'b': 1, 'c': 0, 'd': 3}

Adapt a dictionary depending on the values

I have the following problem: I create a dictionary in which the keys are IDs (0 to N) and the values are list of one or more numbers.
D = dict()
D[0] = [1]
D[1] = [2]
D[2] = [0]
OR:
D = dict()
D[0] = [1, 2]
D[1] = [1, 2]
D[2] = [0]
When the list stored in dictionary has more than one value, it always means that this list is present under 2 different keys. What I now want is to convert both dict into this:
D = dict()
D[0] = 1
D[1] = 2
D[2] = 0
For the first one, it's simple, the function will simply replace the values of the dict by the first value in the list:
def transform_dict(D):
for key, value in D.items():
D[key] = value[0]
return D
However, in the second case, the function must assign one of the key with one of the value, and the second with another. For instance, the key "0" can be assign the value "1" or "2"; and the key "1" will be assign the other one.
I am struggling with this simple problem, and I don't see a way to do this efficiently. Do you have any idea?
EDIT: Explanation n°2
The initial dict can have the following format:
D[key1] = [val1]
D[key2] = [val2]
D[key3] = [val3, val4]
D[key4] = [val3, val4]
If a list of values is composed of more than one element, it means that a second key exist within the dictionnary with the same list of values (key3 and key4).
The goal is to transform this dict into:
D[key1] = val1
D[key2] = val2
D[key3] = val3
D[key4] = val4
Where val3 and val4 are attributed to key3 and key4 in whatever way (I don't care which one goes with which key).
EDIT2: Examples:
# Input dict
D[0] = [7]
D[1] = [5]
D[2] = [4]
D[3] = [1, 2, 3]
D[4] = [6, 8]
D[5] = [1, 2, 3]
D[6] = [1, 2, 3]
D[7] = [6, 8]
#Output
D[0] = 7
D[1] = 5
D[2] = 4
D[3] = 1
D[4] = 6
D[5] = 2
D[6] = 3
D[7] = 8
You can also create a class which behaves likes a dictionary. That way you don't need any additional functions to "clean" the dictionary afterwards but rather solve it on the fly :)
How it works:
We extend collections.abc.Mapping and overwrite the standard dictionary functions __getitem__, __setitem__ and __iter__. We use self._storage to save the actual dictionary.
We use a second dictionary _unresolved to keep track of the keys which haven't been resolved yet. In the example above it for example has the entry (1, 2, 3): [4, 5].
We use a helper function _resolve() that checks if the len((1,2,3)) == len([4,5]). On the moment you assign D[6] this lengths are equal, and the items are assigned to self._storage.
Tried to add comments in the code.
from collections.abc import Mapping
from collections import defaultdict
class WeirdDict(Mapping):
def __init__(self, *args, **kw):
self._storage = dict() # the actual dictionary returned
self._unresolved = defaultdict(list) # a reversed mapping of the unresolved items
for key, value in dict(*args, **kw).items():
self._unresolved_vals[value].append(key)
self._resolve()
def __getitem__(self, key):
return self._storage[key]
def __setitem__(self, key, val):
""" Setter. """
if type(val) == int:
self._storage[key] = val
elif len(val) == 1:
self._storage[key] = val[0]
elif key not in self._storage:
self._unresolved[tuple(val)].append(key)
self._resolve()
def _resolve(self):
""" Helper function - checks if any keys can be resolved """
resolved = set()
for val, keys in self._unresolved.items(): # left to resolve
if len(val) == len(keys): # if we can resolve (count exhausted)
for i, k in enumerate(keys):
self._storage[k] = val[i]
resolved.add(val)
# Remove from todo list
for val in resolved:
del self._unresolved[val]
def __iter__(self):
return iter(self._storage)
def __len__(self):
return len(self._storage)
And then start with:
D = WeirdDict()
D[0] = [7]
D[1] = 5
D[2] = (4)
D[3] = (1, 2, 3)
D[4] = (6, 8)
D[5] = (1, 2, 3)
D[6] = (1, 2, 3)
D[7] = [6, 8]
# Try this for different output
D[7] # gives 8
I am not sure this is the most efficient, but it seems a way of doing it:
in_dict = dict()
in_dict[0] = [7]
in_dict[1] = [5]
in_dict[2] = [4]
in_dict[3] = [1, 2, 3]
in_dict[4] = [6, 8]
in_dict[5] = [1, 2, 3]
in_dict[6] = [1, 2, 3]
in_dict[7] = [6, 8]
out_dict = dict()
out_dict[0] = 7
out_dict[1] = 5
out_dict[2] = 4
out_dict[3] = 1
out_dict[4] = 6
out_dict[5] = 2
out_dict[6] = 3
out_dict[7] = 8
def weird_process(mapping):
result = dict()
for key, val in mapping.items():
if len(val) == 1:
result[key] = val[0]
elif key not in result: # was: `else:`
# find other keys having the same value
matching_keys = [k for k, v in mapping.items() if v == val]
for i, k in enumerate(matching_keys):
result[k] = val[i]
return result
weird_process(in_dict) == out_dict
# True
EDIT: I have simplified the code a little bit.
EDIT2: I have improved the efficiency by skipping elements that have been already processed
EDIT3
An even faster approach would be to use a temporary copy of the input keys to reduce the inner looping by consuming the input as soon as it gets used:
def weird_process(mapping):
unseen = set(mapping.keys())
result = dict()
for key, val in mapping.items():
if len(val) == 1:
result[key] = val[0]
elif key not in result:
# find other keys having the same value
matching_keys = [k for k in unseen if mapping[k] == val]
for i, k in enumerate(matching_keys):
result[k] = val[i]
unseen.remove(k)
return result

How to create a dictionary mapping to set of values to avoid identical keys in a dict

I have the following dictionary that maps a word to the frequency with which that word appears in a text:
{'loves' : 3, 'coding' : 3}
words 'loves' and 'coding' both appeared 3 times in the text and thus have the same value. Now we know that if we want to swap keys and values in this dictionary, it will return this:
either
{3:'loves'}
or this
{3:'coding'}
because identical keys are not allowed in a dictionary
Now my question is how do I swap the keys and features in the dictionary while avoiding duplicate keys as follows:
{3: {'loves', 'coding'}}
This is my failed attempt:
def func(text, words):
d = dict()
for word in text.split():
if word in words:
if word in d:
d[word] += 1
elif word not in d:
d[word] = 1
# return d
newDict = dict()
for key in d:
newKey = d[key]
newDict[newKey] = set()
newDict[newKey].add(key)
return newDict
Edit :
Thanks for all your valuable answers. I also got mine to work by fixing the following bug: a comment is added next to the buggy line
# swapping keys and values in a dictionary:
newDict = dict()
def func(text, words):
d = dict()
for word in text.split():
if word in words:
if word in d:
d[word] += 1
elif word not in d:
d[word] = 1
# return d
newDict = dict()
for key in d:
if d[key] not in newDict:
newDict[d[key]] = set({key}) # This was my bug. Initially I had
# newDict[d[key]] = set()
elif d[key] in newDict:
newDict[d[key]].add(key)
return newDict
Now if I run it on the following input:
func('Ahmed loves loves coding coding is rewarding', {'loves', 'coding', 'I'})
I get this which is exactly what I wanted:
{2: {'coding', 'loves'}}
First of all,
words 'loves' and 'coding' both appeared 3 times in the text and thus have the same key.
they actually have the same value, not the same key (maybe you mistyped it?).
But you can just do a simple for-loop followed by a simple logic where you check first if the value exist in your new dict; it it does, append to their value; if it doesn't, create a new entry.
d = {'loves' : 3, 'coding' : 3}
new_dict = {}
for key, value in d.items():
if new_dict.get(value, None):
new_dict[value].add(key)
else:
new_dict[value] = {key}
As in #RafaelC's answer, only using sets:
d = {'loves' : 3, 'coding' : 3}
new_dict = {}
for key, value in d.items():
if value not in new_dict:
new_dict[value].add(key)
else:
new_dict[value] = {key}

Separating dictionary into smaller dictionaries

I have a dictionary and want to divide it into smaller dictionaries, for example for:
dic = {1:(2,6), 3:(4,5)}
I want to loop it and have a "current" dictionary current = {1:2, 3:4} for first iteration, and current {1:6, 3:5} for the second iteration. Here's what I've tried (and doesn't work):
dic = {1:(2,6), 3:(4,5)}
for i in range (0,1):
for key in dic:
current = {}
current[key] = dic[key][i]
print (current)
this outputs {3:4} and {3:5}, it skips the key "1" for some reason. How do i fix this?
Also, how do I find the number of the values of the keys assuming every key has equal number of values? e.g. for {2:[3,4,5,7], 3:[1,0,3,1]} that would be 4.
You are overwriting current on each iteration, define it before iterating, and range(0, 1) loops through [0] only:
dic = {1:(2,6), 3:(4,5)}
for i in range(2):
current = {}
for key in dic:
current[key] = dic[key][i]
print(current)
Alternatively, you could create the new dictionaries, iterate through the keys of the original dict and create the dictionaries accordingly:
dic = {1:(2,6), 3:(4,5)}
d1, d2 = {}, {}
for key, v in dic.items():
d1[key], d2[key] = v
print(d1, d2)
Which prints out:
{1: 2, 3: 4} {1: 6, 3: 5}
d1[key], d2[key] = v simply unpacks the value for v in d1[key] and d2[key] accordingly.

Categories