Getting keys with duplicate values in a Groovy map - list

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
}
}

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

Compare dictionaries and delete key:value pairs

I have two list dictionaries.
big_dict = defaultdict(list)
small_dict defaultdict(list)
big_dict = {StepOne:[{PairOne:{key1: value1}}, {PairTwo:{key2: value2}}, {PairThree: {key3: value3}}]}
small_dict = {key1: value1}
Is it possible found subset of second dictionary in 'StepOne' and delete another sub-dictionaries in 'StepOne' key?
I bet there is a more pythonic way to do it, but this should solve your problem:
big_dict = {'A0':[{'a':{'ab':1}, 'b':{'bb':2}, 'c':{'cc':3}}], 'A1':[{'b':{'bb':1}, 'c':{'bb':5}, 'd':{'cc':3}}]}
small_dict = {'bb':2, 'cc':3}
for big_key in big_dict.keys():
for nested_key in big_dict[big_key][0].keys():
ls_small = [ x for x in small_dict if x in big_dict[big_key][0][nested_key]]
if not ls_small:
del big_dict[big_key][0][nested_key]
else:
ls_small = [ y for y in ls_small if small_dict[y] is big_dict[big_key][0][nested_key][y]]
if not ls_small:
del big_dict[big_key][0][nested_key]
ls_small = []
I've added another main dictionary, 'A1' to make it more representative. What this does is it loops through keys of the main dictionary ('A0', 'A1') and then through keys of the first set of nested dictionaries ('a', 'b',...). It selects the nested dictionaries as the 1st element of the lists - values of the main dictionaries.
For each nested dictionary it checks if any of the keys in small_dict are part of it's subdictionary. The sibdictionary is fetched by big_dict[big_key][nested_key] since it's the value of the nested dictionary. If the small_dict keys are found in the subdictionary, they are temporarily stored in ls_small.
If ls_small for that nested dictionary is empty after key-checking step it means no keys from small_dict are present in that nested dictionary and the nested dictionary is deleted. If it is not empty, the else part checks for matching of the values - again deleting the entry if the values don't match.
The output for this example is:
{'A1': [{'d': {'cc': 3}}], 'A0': [{'c': {'cc': 3}, 'b': {'bb': 2}}]}
Note - as it is right now, the approach will keep the nested dictionary if only one small_dict key:value pair matches, meaning that an input of this form
big_dict = {'A0':[{'a':{'bb':2}, 'b':{'bb':2, 'cc': 5}, 'c':{'cc':3}}], 'A1':[{'b':{'bb':1}, 'c':{'bb':5}, 'd':{'cc':3}}]}
will produce
{'A1': [{'d': {'cc': 3}}], 'A0': [{'a': {'bb': 2}, 'c': {'cc': 3}, 'b': {'cc': 5, 'bb': 2}}]}
Is this the desired behavior?

Number of indirect employees interview challenge in Python

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)

How do i check for duplicate values present in a Dictionary?

I want to map a function that takes a dictionary as the input and returns a list of the keys.
The keys in the list must be of only the unique values present in the dictionary.
So, this is what I have done.
bDict={}
for key,value in aDict.items():
if bDict.has_key(value) == False:
bDict[value]=key
else:
bDict.pop(value,None)
This is the output :
>>> aDict.keys()
Out[4]: [1, 3, 6, 7, 8, 10]
>>> aDict.values()
Out[5]: [1, 2, 0, 0, 4, 0]
>>> bDict.keys()
Out[6]: [0, 1, 2, 4]
>>> bDict.values()
Out[7]: [10, 1, 3, 8]
But, the expected output should be for bDict.values() : [*1,3,8*]
This may help.
CODE
aDict = { 1:1, 3:2, 6:0, 7:0, 8:4, 10:0, 11:0}
bDict = {}
for i,j in aDict.items():
if j not in bDict:
bDict[j] = [i]
else:
bDict[j].append(i)
print map(lambda x: x[0],filter(lambda x: len(x) == 1,bDict.values()))
OUTPUT
[1, 3, 8]
So it appears you're creating a new dictionary with the keys and values inverted, keeping pairs where the value is unique. You can figure out which of the items are unique first then build a dictionary off of that.
def distinct_values(d):
from collections import Counter
counts = Counter(d.itervalues())
return { v: k for k, v in d.iteritems() if counts[v] == 1 }
This yields the following result:
>>> distinct_values({ 1:1, 3:2, 6:0, 7:0, 8:4, 10:0 })
{1: 1, 2: 3, 4: 8}
Here is a solution (with two versions of the aDict to test a rand case which failed in another solution):
#aDict = { 1:1, 3:2, 6:0, 7:0, 8:4, 10:0}
aDict = { 1:1, 3:2, 6:0, 7:0, 8:4, 10:0, 11:2}
seenValues = {}
uniqueKeys = set()
for aKey, aValue in aDict.items():
if aValue not in seenValues:
# Store the key of the value, and assume it is unique
seenValues[aValue] = aKey
uniqueKeys.add(aKey)
elif seenValues[aValue] in uniqueKeys:
# The value has been seen before, and the assumption of
# it being unique was wrong, so remove it
uniqueKeys.remove(seenValues[aValue])
print "Remove non-unique key/value pair: {%d, %d}" % (aKey, aValue)
else:
print "Non-unique key/value pair: {%d, %d}" % (aKey, aValue)
print "Unique keys: ", sorted(uniqueKeys)
And this produces the output:
Remove non-unique key/value pair: {7, 0}
Non-unique key/value pair: {10, 0}
Remove non-unique key/value pair: {11, 2}
Unique keys: [1, 8]
Or with original version of aDict:
Remove non-unique key/value pair: {7, 0}
Non-unique key/value pair: {10, 0}
Unique keys: [1, 3, 8]
As a python 2.7 one-liner,
[k for k,v in aDict.iteritems() if aDict.values().count(v) == 1]
Note that the above
Calls aDict.values() many times, once for each entry in the dictionary, and
Calls aDict.values().count(v) multiple times for each replicated value.
This is not a problem if the dictionary is small. If the dictionary isn't small, the creation and destruction of those duplicative lists and the duplicative calls to count() may be costly. It may help to cache the value of adict.values(), and it may also help to create a dictionary that maps the values in the dictionary to the number of occurrences as a dictionary entry value.

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