How to find N% of key and values from a python dictiobary - python-3.x

I have a python dictionary:-
x = {"a": 1, "b": 2, "c": 3, "d":4, "e": 5, "f": 6}
I want to find only the N% of the dictonary's keys and values returned to me.
For instance, out of this dictionary, I want to fetch 50% of the key,value pairs only.
So my output should be :-
{"a": 1, "b": 2, "c": 3}
Any help ?

First calculate the count which corresponds to given percentage and also make sure it is an integer. You can also use floor or ceil functions to round of to integers. Then you can use enumerate as below
x = {"a": 1, "b": 2, "c": 3, "d":4, "e": 5, "f": 6}
percent = 50
count = int(percent*len(x)/100)
output = {}
for i,key in enumerate(x.keys(),1):
if(i>count):
break
output[key] = x[key]
print(output)

If you want to choice randomly N% of the element in a python dictionary, you can use random model.
import random
x = {"a": 1, "b": 2, "c": 3, "d":4, "e": 5, "f": 6}
percent = 50
count = int(percent*len(x)/100)
# get list of all the keys in the dictionary and convert it to a list
keys = x.keys()
keys = list(keys)
# use random.choices to choice randomly count element from the keys list
new_keys = random.choices(keys, k=count)
output = {}
for key in new_keys:
output[key] = x[key]
print(output)
you will get as output
{'d': 4, 'a': 1, 'c': 3}

Related

How to check the values in two dictionaries have the same type?

For example, I have two dictionaries having the same keys:
a = {"a": 1, "b": 2, "c":4.5, "d":[1,2], "e":"string", "f":{"f1":0.0, "f2":1.5}}
b = {"a": 10, "b": 20, "c":3.5, "d":[0,2,4], "e":"q", "f":{"f1":1.0, "f2":0.0}}
and I want to compare the types. My code is something like this:
if type(a["a"]) == type(b["a"]) and type(a["b"]) == type(b["b"]) and type(a["c"]) == type(b["c"]) and type(a["d"]) == type(b["d"]) and type(a["e"]) == type(b["e"]) and type(a["f"]) == type(b["f"]) and type(a["f"]["f1"]) == type(b["f"]["f1"]) and type(a["f"]["f2"]) == type(b["f"]["f2"]):
first_type = type(b["d"][0])
if all( (type(x) is first_type) for x in a["d"] )
#do something
pass
Is there a better way to do it?
You can make a list of the common keys between the dicts:
common_keys = a.keys() & b.keys()
and then iterate over them to check the types:
for k in common_keys:
if type(a[k]) == type(b[k]):
print("Yes, same type! " + k, a[k], b[k])
else:
print("Nope! " + k, a[k], b[k])
and if you wanted to go deeper, check if any of the items are dicts, rinse an repeat
for k in common_keys:
if type(a[k]) == type(b[k]):
print("Yes, same type! " + k, type(a[k]), type(b[k]))
if isinstance(a[k], dict):
ck = a[k].keys() & b[k].keys()
for key in ck:
if type(a[k][key]) == type(b[k][key]):
print("Yes, same type! " + key, type(a[k][key]), type(b[k][key]))
else:
print("Nope!")
else:
print("Nope! " + k, type(a[k]), type(b[k]))
You can use a for loop to iterate through the dicts:
same_types = True
for key in a.keys():
if type(a[key]) != type(b[key]):
same_types = False
break
# if the value is a dict, check nested value types
if type(a[key]) == dict:
for nest_key in a[key].keys():
if type(a[key][nest_key]) != type(b[key][nest_key]):
same_types = False
break
# if the value is a list, check all list elements
# I just simply concat two lists together, you can also refer to
# https://stackoverflow.com/q/35554208/19322223
elif type(a[key]) == list:
first_type = a[key][0]
for elem in a[key] + b[key]:
if type(elem) != first_type:
same_types = False
break
if not same_types:
break
if same_types:
# do something
With the following helper function:
def get_types(obj, items=None):
"""Function that recursively traverses 'obj' and returns
a list of all values and nested values types
"""
if not items:
items = []
if isinstance(obj, dict):
for value in obj.values():
if not isinstance(value, (dict, list, set, tuple)):
items.append(value)
else:
get_types(value, items)
elif isinstance(obj, (list, set, tuple)):
for value in obj:
get_types(value, items)
else:
items.append(obj)
return [type(x) for x in items]
You can compare two dictionaries' values types however deeply nested these are, like this:
if get_types(a) == get_types(b):
print("Each a and b values are of same types")
Since, in your example, a misses one value for d key ([1, 2]) compared to the other dict ([0, 2, 4]), nothing will be printed.
Let's take another example where both dictionaries have the same shape this time, but one value of different type (f2):
a = {"a": 1, "b": [[1, 2], [3, [4]]], "c": {"c1": 0.0, "c2": {"x": "9"}}}
b = {"d": 7, "e": [[2, 1], [5, [7]]], "f": {"f1": 8.9, "f2": {"y": 9}}}
if get_types(a) == get_types(b):
print("Each a and b values are of same types")
Then again, nothing will be printed.
But if you replace 9 by "9" in b["f2"]:
a = {"a": 1, "b": [[1, 2], [3, [4]]], "c": {"c1": 0.0, "c2": {"x": "9"}}}
b = {"d": 7, "e": [[2, 1], [5, [7]]], "f": {"f1": 8.9, "f2": {"y": "9"}}}
if get_types(a) == get_types(b):
print("Each a and b values are of same types")
# Output
# Each a and b values are of same types

How can I improve this algorithm to count the frequency of characters in a string?

In order to sort in a descending manner, the frequency of char appearance in a string, I've developed the following algorithm.
First I pass the string to a dictionary using each char as a key along with its frequency of appearance as value. Afterwards I have converted the dictionary to a descending sorted multi-dimension list.
I'd like to know how to improve the algorithm, was it a good approach? Can it be done diferently? All proposals are welcome.
#Libraries
from operator import itemgetter
# START
# Function
# String to Dict. Value as freq.
# of appearance and char as key.
def frequencyChar(string):
#string = string.lower() # Optional
freq = 0
thisDict = {}
for char in string:
if char.isalpha(): # just chars
freq = string.count(char)
thisDict[char] = freq # {key:value}
return(thisDict)
str2Dict = frequencyChar("Would you like to travel with me?")
#print(str2Dict)
# Dictionary to list
list_key_value = [[k,v] for k, v in str2Dict.items()]
# Descending sorted list
list_key_value = sorted(list_key_value, key=itemgetter(1), reverse=True)
print("\n", list_key_value, "\n")
#END
You're doing way too much work. collections.Counter counts things for you automatically, and even sorts by frequency:
from collections import Counter
s = "Would you like to travel with me?"
freq = Counter(s)
# Counter({' ': 6, 'o': 3, 'l': 3, 'e': 3, 't': 3, 'u': 2, 'i': 2, 'W': 1, 'd': 1, 'y': 1, 'k': 1, 'r': 1, 'a': 1, 'v': 1, 'w': 1, 'h': 1, 'm': 1, '?': 1})
If you want to remove the spaces from the count:
del freq[' ']
# Counter({'o': 3, 'l': 3, 'e': 3, 't': 3, 'u': 2, 'i': 2, 'W': 1, 'd': 1, 'y': 1, 'k': 1, 'r': 1, 'a': 1, 'v': 1, 'w': 1, 'h': 1, 'm': 1, '?': 1})
Also just in general, your algorithm is doing too much work. string.count involves iterating over the whole string for each character you're trying to count. Instead, you can just iterate once over the whole string, and for every letter you just keep incrementing the key associated with that letter (initialize it to 1 if it's a letter you haven't seen before). That's essentially what Counter is doing for you.
Spelling it out:
count = {}
for letter in the_string:
if not letter.isalpha():
continue
if letter not in count:
count[letter] = 1
else:
count[letter] += 1
And then to sort it you don't need to convert to a list first, you can just do it directly:
ordered = sorted(count.items(), key=itemgetter(1), reverse=True)

Adding values of one dictionary if the keys match the keys of the other dictionary

I am new to python. I'd like to ask for your assistance regarding operations with dictionaries. I guess, the question is a bit basic. But, I'm kinda stuck.
I need to get the total of values in dict2 corresponding the "JJ" values in dict1. Since "JJ" in dict1 is associated with keys "A" and "B", the corresponding values in dict2 are 30 and 100, which sums to 130
Thank you!
Rn
My code (I'm getting the sum of all values in dict2=145 after step 2 instead of just A+B=130)
dict1 = {"A":"JJ", "B":"JJ", "C":"X"}
dict2 = {"A":30, "B":100, "C":15}
dict3=dict()
for (kk, vv) in dict1.items():
ref_val="JJ"
if vv == ref_val:
dict3[kk] = vv
print(dict3)
total_points=0
for (kk, vv) in dict2.items():
for (kk, vv) in dict3.items():
total_points = sum(vv for vv in dict2.values())
print(total_points)
I hope I understood the question correctly.
I so, this should work:
dict1 = {"A": "JJ", "B": "JJ", "C": "X"}
dict2 = {"A": 30, "B": 100, "C": 15}
keys = set(k for k, v in dict1.items() if v == "JJ")
total_points = sum(dict2.get(k, 0) for k in keys)
print(total_points)
keys: using list comprehension the keys having value equal to JJ are selected
total_points: the values corresponding to those keys are fetch from dict2 and summed on the fly. If a key from keys is not present in dict2 (which is not the case, btw) 0 (zero) is fetched instead (so it won't affect the sum)
I like the other answer but I would probably solve this problem a little more generically:
from collections import defaultdict
dict1 = {"A": "JJ", "B": "JJ", "C": "X"}
dict2 = {"A": 30, "B": 100, "C": 15}
val_to_keys = defaultdict(list)
for key, val in dict1.items():
val_to_keys[val].append(dict2.get(key, 0))
# Note that now val_to_keys contains:
# {'JJ': [30, 100], 'X': [15]}
if 'JJ' in val_to_keys:
print(sum(val_to_keys['JJ'])) # 130
# or you can one line the print
print(sum(val_to_keys.get('JJ', []))) # 130
This way you can only need to iterate over the dict1 once and you can pull out any value you want.
Note that if all you care about is the sums then it can be even more efficient by calculating the sum during the initial iteration. (I use a normal dict instead of a defaultdict here just to show how you can do it both with regular dictionaries and defaultdicts).
dict1 = {"A": "JJ", "B": "JJ", "C": "X"}
dict2 = {"A": 30, "B": 100, "C": 15}
val_to_keys = {}
for key, val in dict1.items():
val_to_keys[val] = val_to_keys.get(val, 0) + dict2.get(key, 0)
# Note that now val_to_keys contains:
# {'JJ': 130, 'X': 15}
if 'JJ' in val_to_keys:
print(val_to_keys['JJ']) # 130

How to multiply values of matching keys together?

x = {"a": 1, "b": 2, "c": 3}
y = {"b": 4, "c": 5, "d": 6}
for key in x:
if key in y:
a = (x[key])
b = (y[key])
This returns a as 2 3 and b as 4 5. What i'm trying to do is multiply the matching key values together and then add those values together. I am not quite sure how to do this. If you guys could help me out that would be great. Thank you in advanced.
A simple way to do this would be to just keep a running total, e.g.:
total = 0
for key in x:
if key in y:
a = x[key]
b = y[key]
total += a*b
print(total) # 23
But python has powerful comprehensions/generators that can simplify this to:
>>> sum(x[key]*y[key] for key in x if key in y)
23
You can use sum with a generator:
x = {"a": 1, "b": 2, "c": 3}
y = {"b": 4, "c": 5, "d": 6}
sum(x[k] * y[k] for k in set(x) & set(y))
# 23

counting letter frequency with a dict

I'm trying to find the frequency of letters without the Counter.And the code will output a dictionary form of result. And what I have done so far is to make the program count the word frequencies but not the letter/character frequencies. If anyone could point out my mistakes in this code that would be wonderful. Thank you.
It supposed to look like this:
{'a':2,'b':1,'c':1,'d':1,'z':1}
**but this is what I am actually getting:
{'abc':1,'az':1,'ed':1}
**my code is below
word_list=['abc','az','ed']
def count_letter_frequency(word_list):
letter_frequency={}
for word in word_list:
keys=letter_frequency.keys()
if word in keys:
letter_frequency[word]+=1
else:
letter_frequency[word]=1
return letter_frequency
Use collections.Counter
from collections import Counter
print Counter(''.join(word_list))
# Counter({'a': 2, 'c': 1, 'b': 1, 'e': 1, 'd': 1, 'z': 1})
Or count the elements yourself if you don't want to use Counter.
from collections import defaultdict
d = defaultdict(int)
for c in ''.join(word_list):
d[c] += 1
print d
# defaultdict(<type 'int'>, {'a': 2, 'c': 1, 'b': 1, 'e': 1, 'd': 1, 'z': 1})
This is the correct code:
word_list=['abc','az','ed']
def count_letter_frequency(word_list):
letter_frequency={}
for word in word_list:
for letter in word:
keys=letter_frequency.keys()
if letter in keys:
letter_frequency[letter]+=1
else:
letter_frequency[letter]=1
return letter_frequency
You were iterating over the list and the list contains words. So, you were making words as keys in your dictionary. So, you have to add another for loop to iterate over the letters in each word.
Would this be acceptable:
flat = ''.join(word_list)
{l: flat.count(l) for l in set(flat)}
#{'a': 2, 'b': 1, 'c': 1, 'd': 1, 'e': 1, 'z': 1}
If you would prefer this in for loop, here it goes:
flat = ''.join(word_list)
result = {}
for l in flat:
if l in result:
result[l] += 1
else:
result[l] = 1

Resources