Sort a dictionary a value - python-3.x

I know that this problem has been discussed, but none of the answers refer to a string as a key. I would like to sort a dictionary by a value - descending and ascending. Here are my sketches:
def ascending(d):
from operator import itemgetter
sorted(d.items(), key=itemgetter(1))
return d
f={'a': 2, 'c': 1, 'f': 5, 'e': 4}
g={'s': 3, 'y': 1, 'r': 7, 'h': 4}
print(hj(f))
def descending(d):
from operator import itemgetter
sorted(d.items(), key=itemgetter(1), reverse=True)
return d
print(jh(g))
However, I get:
{'a': 2, 'c': 1, 'f': 5, 'e': 4}
{'h': 4, 'r': 7, 'y': 1, 's': 3}
What am I doing wrong? How can I improve the code?
OK, a little ask for explanation:
I have solved problem, using:
def ascending(d):
from operator import itemgetter
p=sorted(d.items(), key=itemgetter(1))
return p
f={'a': 2, 'c': 1, 'f': 5, 'e': 4}
g={'s': 3, 'y': 1, 'r': 7, 'h': 4}
print(hj(f))
def descending(d):
from operator import itemgetter
p=sorted(d.items(), key=itemgetter(1), reverse=True)
return p
print(jh(g))
How does sorted() works, if it doesn't affected d in 'return d'?

... but none of the answers refer to a string as a key.
That's not relevant.
What am I doing wrong?
There is a big difference between sort() and sorted(). The 1st is evaluated for side effects, and returns None. The 2nd leaves its argument untouched, and creates a brand new list in sorted order.
sorted(d.items(), key=itemgetter(1))
return d
You evaluated an expression (which did not change d), and then silently discarded the result. Then you returned the same old d.
You want to return sorted( ... ) instead.
How can I improve the code?
Thank you for asking, that's a terrific question! Do keep asking it of yourself.
PEP8 asks that you put import statements at top of source file, please.

Related

How can I go through different dictionaries using nested loop?

sem1_credit = {'A': 4, 'B': 4, 'C': 3}
sem2_credit = {'D': 5, 'E': 1}
sem3_credit = {'F': 3}
e = 2
for j in range(e):
for i in 'sem'+str(j+1)+'_credit':
I wanted to use loop to access different dict. So I tried to create the dict name with concatenation using loop. But it doesn't work. Is there a way to work it out or is there some other way to approach dict without loops.
You can get a dictionary of the current local symbols table by calling locals(). So locals()['sem1_credit'] is essentially this sem1_credit.
From here, you can build a loop:
sem1_credit = {'A': 4, 'B': 4, 'C': 3}
sem2_credit = {'D': 5, 'E': 1}
sem3_credit = {'F': 3}
for idx in range(1, 4):
credits = locals()[f'sem{idx}_credit']
for key, credit in credits.items():
print(f"{key} {credit}")
Keep in mind that the range(num) generate numbers from 0 to num-1. So in your code, range(2) only generates 0 and 1.

Python get random value when using min() when there is more than one match

I have the following code:
dict = {'a': 1, 'b': 2, 'c': 5, 'd':1, 'e': 5, 'f': 1}
get_min = min(dict, key=dict.get)
As you can see here there is actually three min() matches "a", "d" and "f" with the value of 1.
This will return "a" 100% of the time as that is what min() is designed to do from what I am reading. However, I have a need where I would like to randomly get back "a", "d" or "f" instead of just "a".
Is there a way I can do this using min() or some other way (maybe lambda, I am not very good at it)? I thought this would be pretty simple but it turns out it is not :P. I can get this working with some for loops and creating lists but I was looking for the shortest way possible.
Your thoughts would be appreciated!
Thanks,
jAC
Here is one solution:
import random
dic = {'a': 1, 'b': 2, 'c': 5, 'd':1, 'e': 5, 'f': 1}
a = random.choice([k for k,v in dic.items() if v == min(dic.values())])
np.random.choice([k for k in dict.keys() if dict[key]==min(dict.values())])

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)

Converting specific values from a dictionary to float

I have this dictionary
dict_X = {
'A': {'a': 371, 'b': 4925, 'c': 39, 'd': 8},
'B': {'a': 400, 'b': 4659, 'c': 37, 'd': 11},
'C': {'a': 19, 'b': 214, 'c': 1, 'd': 1},
'D': {'a': 16, 'b': 115, 'c': 0, 'd': 1}
}
I need to convert the values of 'c' and 'd' to float and find ratio of 'c' to 'd'.
I know that I have to use float() method, what I cannot figure out is how to use that for the values in a dictionary within a dictionary.
Need to convert the values to 'c' and 'd' to float to find the ratio of 'c':'d'. Thank you guys for the help.
The code you posted in the comments is almost correct, except you forgot to retain the keys for the inner dict, making the nested structures sets instead. The correct dict comprehension would be:
{outer_k: {inner_k: float(inner_v) for inner_k, inner_v in outer_v.items()} for outer_k, outer_v in dict_X.items()}
However, this converts all the values (a,b,c,d) into floats instead of just c and d. You can limit it to only those keys using the following if-else condition:
{outer_k: {inner_k: float(inner_v) if inner_k in ['c','d'] else inner_v for inner_k, inner_v in outer_v.items()} for outer_k, outer_v in dict_X.items()}
Or, since according to what you said you only need the float conversion for a calculation, just cast it before using it in that expression and leave dict_X as it is. For example,
float_ratio = float(dict_X['A']['c'])/dict_X['A']['d']
Converting just one of them is enough to make the result a float.

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