Number of indirect employees interview challenge in Python - python-2.7

An example interview question I have seen come up several times is
Given a mapping of employee_id to boss_id (for direct chain of command
only), return how many employees each boss indirectly manages.
I have found several solutions in SQL but can't find any examples of pythonic approaches.
More detailed problem definition:
Imagine that we have a dict containing the employee_id and the boss_id. In the example below C is manager of A, C is also manager of B, F is manager of C and so on. F is the manager of themselves and therefore the root of the hierarchy (i.e. the CEO). Each employee directly reports to exactly one manager.
emp_boss_map = dict([
("A","C"),
("B","C"),
("C","F"),
("D","E"),
("E","F"),
("F","F")])
Write a function to build a dictionary of the quantity of employees under each employee, not just their direct reports.
Output should be the following for example above:
{A:0,B:0,C:2,D:0,E:1,F:5}
How would one approach this problem in Python?
UPDATE:
Upon #prune 's suggestion I reversed the dict using
newdict = {}
for key, value in emp_boss_map.items():
for string in value:
newdict.setdefault(string, []).append(key)
Which returns
{'C': ['A', 'B'], 'E': ['D'], 'F': ['C', 'E', 'F']}

This is a closure problem on a tree. First and foremost, invert (reverse) the dictionary. From then, it's a straightforward count of nodes in each sub-tree, a recursive algorithm on each individual node: recur on each child, sum their return values, add 1 for each child, and that's the total direct reports for the current node.
Does that get you moving?
full_report = {}
def report_count(node):
global full_report
report_list = newdict[node]
count = len(report_list) # start with quantity of direct reports
# Find number of reports for each of those reports
for report in report_list:
count += report_count(report)
full_report[node] = count # add entry for this node to global count list
return count + len(report_list) # return this count to supervisor
I've left a lot of details open for you, such as finding all of the root nodes (from the original dictionary) and perhaps finding something better than a global variable for the master list.
Does that get you to the final solution?

You can solve this problem by reversing a dictionary and traversing it recursively till the end.
result_count=[]
def get_me_the_children(root):
if reverse_d.get(root,0) == 0:
return
for _ in reverse_d.get(root,0):
if _== root:
continue
else:
get_me_the_children(_)
print(_,end=" ")
result_count.append(_)
if __name__ == "__main__":
input_d = {"A":"A","B":"A","C":"B","D":"B","E":"D","F":"E"}
reverse_d={}
result_count_dict = {}
for key,values in input_d.items():
reverse_d.setdefault(values,[])
reverse_d[values].append(key)
#reverse_d = {'A': ['A', 'B'], 'B': ['C', 'D'], 'D': ['E'], 'E': ['F']}
for key,value in input_d.items():
result_count=[]
print(key,end=": ")
get_me_the_children(key)
result_count_dict[key] = len(result_count)
print("")
print(result_count_dict) #{'A': 5, 'B': 4, 'C': 0, 'D': 2, 'E': 1, 'F': 0}
"""output:
A: C F E D B
B: C F E D
C:
D: F E
E: F
F:
"""

def m1(dict):
new_dict = {}
keys_list = {keys for keys in dict.keys()}
for key, val in dict.items():
if key==val:
continue
if val not in new_dict.keys():
new_dict[val] = 1
else:
new_dict[val] = new_dict[val] + 1
if key in new_dict.keys():
new_dict[val] = new_dict[val] + new_dict[key]
for keys in keys_list:
if keys not in new_dict.keys():
new_dict[keys]=0
print(new_dict)
emp_boss_map={'A': 'C', 'B': 'C', 'C': 'F', 'D': 'E', 'E': 'F', 'F': 'F'}
m1(emp_boss_map)

Related

How to get specific values from a dictionary using list comprehension and modify them?

Can someone help and kindly advise how Can I get specific values from this dictionary (Using list comprehension) and
square the values only,
change every string value, so it starts with upper case?
items_list = {'a': 3, 'b':6, 'c': 'short', 'h': 'example', 'p': 77}
So, the output needs to be:
9, 36, 5929
Short, Example
(Python):
items_list = {'a': 3, 'b': 6, 'c': 'short', 'h': 'example', 'p': 77}
lst = [v ** 2 if isinstance(v, (int, float)) else v.capitalize() for v in
items_list.values()]
print(lst)
output:
[9, 36, 'Short', 'Example', 5929]
The exact output that you showed can not be produced using single list comprehension, because the iteration is in order.
yes, you need to iterate through the dictionary and check if the value is an int then square it and if it is not capitalize it
result = []
for key, value in dictionary.items()
if type(value) is int:
result.append(value**2)
else:
result.append(value.capitalize())
print(result)
this should print the desired output

Convert text list into Dictionary?

I have a list as the given one:
l = ['1,a','2,b','3,c']
I want to convert this list into a Dictionary, like this:
l_dict = {1:'a',2:'b',3:'c'}
How can I solve it?
you can use a generator expression to pass to the dict constructor each string split by ','
dict(e.split(',') for e in l)
output:
{'1': 'a', '2': 'b', '3': 'c'}
You need to first split and then push the value to dict. Here there are two options if you just want to push it to dict you can use list else if you want in order use od
Link
from collections import OrderedDict
l = ['1,a','2,b','3,c']
list = {}
od = OrderedDict()
for text in l:
convertToDict = text.split(",")
list[convertToDict[0]] = convertToDict[1]
od[convertToDict[0]] = convertToDict[1]
print(list)
print(od)

PYTHON 2.7 - Modifying List of Lists and Re-Assembling Without Mutating

I currently have a list of lists that looks like this:
My_List = [[This, Is, A, Sample, Text, Sentence] [This, too, is, a, sample, text] [finally, so, is, this, one]]
Now what I need to do is "tag" each of these words with one of 3, in this case arbitrary, tags such as "EE", "FF", or "GG" based on which list the word is in and then reassemble them into the same order they came in. My final code would need to look like:
GG_List = [This, Sentence]
FF_List = [Is, A, Text]
EE_List = [Sample]
My_List = [[(This, GG), (Is, FF), (A, FF), (Sample, "EE), (Text, FF), (Sentence, GG)] [*same with this sentence*] [*and this one*]]
I tried this by using for loops to turn each item into a dict but the dicts then got rearranged by their tags which sadly can't happen because of the nature of this thing... the experiment needs everything to stay in the same order because eventually I need to measure the proximity of tags relative to others but only in the same sentence (list).
I thought about doing this with NLTK (which I have little experience with) but it looks like that is much more sophisticated then what I need and the tags aren't easily customized by a novice like myself.
I think this could be done by iterating through each of these items, using an if statement as I have to determine what tag they should have, and then making a tuple out of the word and its associated tag so it doesn't shift around within its list.
I've devised this.. but I can't figure out how to rebuild my list-of-lists and keep them in order :(.
for i in My_List: #For each list in the list of lists
for h in i: #For each item in each list
if h in GG_List: # Check for the tag
MyDicts = {"GG":h for h in i} #Make Dict from tag + word
Thank you so much for your help!
Putting the tags in a dictionary would work:
My_List = [['This', 'Is', 'A', 'Sample', 'Text', 'Sentence'],
['This', 'too', 'is', 'a', 'sample', 'text'],
['finally', 'so', 'is', 'this', 'one']]
GG_List = ['This', 'Sentence']
FF_List = ['Is', 'A', 'Text']
EE_List = ['Sample']
zipped = zip((GG_List, FF_List, EE_List), ('GG', 'FF', 'EE'))
tags = {item: tag for tag_list, tag in zipped for item in tag_list}
res = [[(word, tags[word]) for word in entry if word in tags] for entry in My_List]
Now:
>>> res
[[('This', 'GG'),
('Is', 'FF'),
('A', 'FF'),
('Sample', 'EE'),
('Text', 'FF'),
('Sentence', 'GG')],
[('This', 'GG')],
[]]
Dictionary works by key-value pairs. Each key is assigned a value. To search the dictionary, you search the index by the key, e.g.
>>> d = {1:'a', 2:'b', 3:'c'}
>>> d[1]
'a'
In the above case, we always search the dictionary by its keys, i.e. the integers.
In the case that you want to assign the tag/label to each word, you are searching by the key word and finding the "value", i.e. the tag/label, so your dictionary would have to look something like this (assuming that the strings are words and numbers as tag/label):
>>> d = {'a':1, 'b':1, 'c':3}
>>> d['a']
1
>>> sent = 'a b c a b'.split()
>>> sent
['a', 'b', 'c', 'a', 'b']
>>> [d[word] for word in sent]
[1, 1, 3, 1, 1]
This way the order of the tags follows the order of the words when you use a list comprehension to iterate through the words and find the appropriate tags.
So the problem comes when you have the initial dictionary indexed with the wrong way, i.e. key -> labels, value -> words, e.g.:
>>> d = {1:['a', 'd'], 2:['b', 'h'], 3:['c', 'x']}
>>> [d[word] for word in sent]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'a'
Then you would have to reverse your dictionary, assuming that all elements in your value lists are unique, you can do this:
>>> from collections import ChainMap
>>> d = {1:['a', 'd'], 2:['b', 'h'], 3:['c', 'x']}
>>> d_inv = dict(ChainMap(*[{value:key for value in values} for key, values in d.items()]))
>>> d_inv
{'h': 2, 'c': 3, 'a': 1, 'x': 3, 'b': 2, 'd': 1}
But the caveat is that ChainMap is only available in Python3.5 (yet another reason to upgrade your Python ;P). For Python <3.5, solutions, see How do I merge a list of dicts into a single dict?.
So going back to the problem of assigning labels/tags to words, let's say we have these input:
>>> d = {1:['a', 'd'], 2:['b', 'h'], 3:['c', 'x']}
>>> sent = 'a b c a b'.split()
First, we invert the dictionary (assuming that there're one to one mapping for every word and its tag/label:
>>> d_inv = dict(ChainMap(*[{value:key for value in values} for key, values in d.items()]))
Then, we apply the tags to the words through a list comprehension:
>>> [d_inv[word] for word in sent]
[1, 2, 3, 1, 2]
And for multiple sentences:
>>> sentences = ['a b c'.split(), 'h a x'.split()]
>>> [[d_inv[word] for word in sent] for sent in sentences]
[[1, 2, 3], [2, 1, 3]]

print dictionary key's minus the list variables

So i'm trying to make the game scrabble but i have a little problem and i will try to explain it as good as i can:
I have written a function that generates a dictionary with 7 key's (the key's are the letters you get in your scrabble game and the value of the key means how much times i have that letter in my hand)
def deal_hand (7)
generates for example the code:
{'a': 1, 'b': 2, 'k': 1, 'o': 1, 'p': 1, 'r': 1}
This means we have the following letters: a, b, b, k, o, p, r (we have 2 times a B because the value of that key is 2.
But now i want to create a 2nd function named update_hand, this function should take the word the user made out of the word_list (in this example something like the word 'bob') and should return one of the following 2 dictionaries
{'a': 1, 'b': 0, 'k': 1, 'o': 0, 'p': 1, 'r': 1}
{'a': 1, 'k': 1, 'p': 1, 'r': 1}
My program should return one of these programs because the user used the letters : B, O and B. so there are no B's and O's left.
I have tried a lot to solve this problem now and i came up with the following function:
def update_hand(word, hand):
newd = {}
for x in word:
if x in newd:
newd[x]+=1
else:
newd[x] = 1
hand[x]-=1
return newd
in this code the values of the word and hand in the function are:
test_word = raw_input("Enter the word you want to make out of these letters.")
print update_hand(test_word,de_letters)
I think im pretty close but i just get the output of the last letter i enter, please help me! :o
def update_hand(hand, name):
delkeys = []
for n in name:
if not hand[n]:
raise ValueError("Cannot remove %s from hand" %n)
hand[n] -= 1
if not hand[n]:
delkeys.append(n)
for k in delkeys:
hand.pop(k)
return hand

Getting keys with duplicate values in a Groovy map

I just came up with this problem while exploring groovy, I have a Map and i wanted to get the keys with the same values from that map.
Map maps = ['a': 10, 'b': 10, 'c': 11, 'd': 12]
is it possible to get only the keys with same values, what i wanted to get from this example is a list with values:
List keys = ['a','b']
I have a solution for this problem and it's a long line of codes, I'm just wondering if it is possible to solve this using findAll in Map. I'm having a hard time counting the values in the map.
thanks for sharing your ideas.
If you know which value you need the keys for, then you can use the findAll method to get all the entries that have that value and then get the keys with keySet or by using the splat operator as *.key:
def keysForValue(map, value) {
map.findAll { it.value == value }*.key
}
def map = ['a': 10, 'b': 10, 'c': 11, 'd': 12]
assert keysForValue(map, 10) == ['a', 'b']
assert keysForValue(map, 12) == ['d']
assert keysForValue(map, 13) == []
In case you don't know which value should have the repeated keys, and all you want is to get the keys that have a repeated value (if there's any), you can try something like:
def getKeysWithRepeatedValue(map) {
map.groupBy { it.value }.find { it.value.size() > 1 }?.value*.key
}
It first groups the map entries by value, so the result of map.groupBy { it.value } for the example map is [10:[a:10, b:10], 11:[c:11], 12:[d:12]]. Then it finds the first entry in that map that has a list with more than one element as a value; that entry corresponds with the value that has more than one key associated with it. The result of .find { it.value.size() > 1 } would be the map entry 10={a=10, b=10}. The last conditional navigation and splat operator ?.value*.key is to get the value of that entry in case it exists and then get keys of that value. Usage:
assert getKeysWithRepeatedValue(['a': 10, 'b': 10, 'c': 11, 'd': 12]) == ['a', 'b']
// If no value has more than one key, returns null:
assert getKeysWithRepeatedValue(['a': 10, 'c': 11, 'd': 12]) == null
// If more than one value has repeated keys, returns the keys that appear first:
assert getKeysWithRepeatedValue(['a': 10, 'b': 11, 'c': 10, 'd': 11]) == ['a', 'c']
You mean
Map maps = ['a': 10, 'b': 10, 'c': 11, 'd': 12]
perhaps? Easy enough, but a map does not preserve the ordering of elements. You can retrieve a list of keys in no particular order with:
List output = maps.keySet() as List
Or if you want to reverse the map, and find a list of keys for each value, you can use this:
Map output = maps.groupEntriesBy {
it.value
}.each {
it.value = it.value.collect {
it.key
}
}