So I created this code with the help of Stack Overflow users.
def get_name(string):
return string.replace(" ", "").replace("-", "")
def gnames(input_list: list):
output = {}
for entry in input_list:
if '->' in entry:
names = entry.split('->')
output[names[1]] = output[names[0]]
output[names[0]] = 0
else:
name = get_name(entry)
if name not in output:
output[name] = 0
if " " in entry:
output[name] = 1
if "--" in entry:
output[name] -= 1
return output
print(gnames(["Jim--", "John--", "Jordan--", "Jim ", "John--", "Jeff--", "June ", "June->Jim"]))
and this returns
{'Jim': 1, 'John': -2, 'Jordan': -1, 'Jeff': -1, 'June': 0}
Now this is right, but I want gnames()
to return only the non zero values negative numbers or positive numbers are fine
so in my example, there's 'June' = 0
and I want the output of gnames()
to exclude 'June' = 0
or if any other person has a 0... I want gnames()
to exclude it...
so my output in thiscase, should return
{'Jim': 1, 'John': -2, 'Jordan': -1, 'Jeff': -1}
How can I do that??
CodePudding user response:
A dictionary comprehension makes this pretty simple. If we start out with gnames
being {'Jim': 1, 'John': -2, 'Jordan': -1, 'Jeff': -1, 'June': 0}
we can write a dictionary comprehension that will filter out the zero value.
>>> gnames = {'Jim': 1, 'John': -2, 'Jordan': -1, 'Jeff': -1, 'June': 0}
>>> {k: v for k, v in gnames.items() if v != 0}
{'Jim': 1, 'John': -2, 'Jordan': -1, 'Jeff': -1}
>>>
CodePudding user response:
Also using dictionary comprehension, you can alter your return like so:
return {x:output[x] for x in output if output[x] != 0}
Description of what this does:
# for each element in output
# if element['name'] != 0 then keep it
Full code:
def get_name(string):
return string.replace(" ", "").replace("-", "")
def gnames(input_list: list):
output = {}
for entry in input_list:
if '->' in entry:
names = entry.split('->')
output[names[1]] = output[names[0]]
output[names[0]] = 0
else:
name = get_name(entry)
if name not in output:
output[name] = 0
if " " in entry:
output[name] = 1
if "--" in entry:
output[name] -= 1
return {x:output[x] for x in output if output[x] != 0}
print(gnames(["Jim--", "John--", "Jordan--", "Jim ", "John--", "Jeff--", "June ", "June->Jim"]))
# Sample output
# {'Jim': 1, 'John': -2, 'Jordan': -1, 'Jeff': -1}
CodePudding user response:
If you want to avoid an explicit in
check to see if the key exists in the dictionary first else set a default value of 0
, you can use a collections.defaultdict
which is a dict
sub-type which automatically sets a default value if the key is not in dict.
So your code could be simplified with defaultdict(int)
, then with a sign to delta (change) mapping for a slight improvement, then finally you can opt to delete key from the dict
if the result of addition is a 0
value; this can be used to avoid the need of a dict
comprehension in the return statement altogether.
So now with all the changes added, the end-to-end code looks like below:
from collections import defaultdict
def get_name(string):
return string.replace(" ", "").replace("-", "")
def gnames(input_list: list):
output = defaultdict(int)
sign_to_delta = {' ': 1,
'--': -1}
for entry in input_list:
if '->' in entry:
from_, to = entry.split('->')
# Use `pop` to retrieve and also delete the key from dict
# instead of assigning the value as 0, which is already the
# default behavior if the key is not present.
output[to] = output.pop(from_)
else:
name = get_name(entry)
for sign in sign_to_delta:
if sign in entry:
result = output[name] sign_to_delta[sign]
if result:
output[name] = result
else:
del output[name]
return output
print(gnames(["Jim--", "John--", "Jordan--", "Jim ", "John--", "Jeff--", "June ", "June->Jim"]))
print(gnames(["Jean ", "Jean--", "Jean--", "Jean "]))
Out:
defaultdict(<class 'int'>, {'John': -2, 'Jordan': -1, 'Jeff': -1, 'Jim': 1})
defaultdict(<class 'int'>, {})