Dictionary programs¶
From GeeksforGeeks Python Programming Examples
Follow links to the originals for more details on the problem and Python solutions.
Sort dictionary by keys or values¶
Sort keys ascending¶
>>> kv = {2:'56', 1:'2', 5:'12', 4:'24', 6:'18', 3:'323'}
>>> sorted(kv.keys())
[1, 2, 3, 4, 5, 6]
q)kv:2 1 4 5 6 3!64 69 23 65 34 76
q)asc key kv
`s#1 2 3 4 5 6
A dictionary is a mapping between two lists: the keys and the values.
Keys are commonly of the same datatype; as are values.
So most dictionaries are a mapping between two vectors. (Homogenous lists.)
Above, dictionary kv
is formed from two vectors by the Dict operator !
.
A list of key-value pairs can be flipped into two lists, and passed to (!).
to form a dictionary.
q)(!). flip(2 56;1 2;5 12;4 24;6 18;3 323)
2| 56
1| 2
5| 12
4| 24
6| 18
3| 323
Sort entries ascending by key¶
>>> [[k, kv[k]] for k in sorted(kv.keys())]
[[1, 2], [2, 56], [3, 323], [4, 24], [5, 12], [6, 18]]
q)k!kv k:asc key kv
1| 2
2| 56
3| 323
4| 24
5| 12
6| 18
Sort entries ascending by value¶
>>> sorted(kv.items(), key = lambda x:(x[1], x[0]))
[(1, 2), (5, 12), (6, 18), (4, 24), (2, 56), (3, 323)]
q)asc kv
1| 2
5| 12
6| 18
4| 24
2| 56
3| 323
The value of kv
is the dictionary’s values.
q)value kv
56 2 12 24 18 323
So an ascending sort of the dictionary returns it in ascending order of values.
Sum of values¶
>>> d = {'a': 100, 'b':200, 'c':300}
>>> sum(d.values())
600
Dictionaries are first-class objects in q, and keywords apply to their values.
q)d:`a`b`c!100 200 300
q)sum d
600
Delete an entry¶
>>> d = {"Arushi" : 22, "Anuradha" : 21, "Mani" : 21, "Haritha" : 21}
>>> # functional removal
>>> {key:val for key, val in d.items() if key != 'Mani'}
{'Arushi': 22, 'Anuradha': 21, 'Haritha': 21}
>>> # removal in place
>>> d.pop('Mani')
21
>>> d
{'Anuradha': 21, 'Haritha': 21, 'Arushi': 22}
q)d:`Anuradha`Haritha`Arushi`Mani!21 21 22 21
q)delete Mani from d / functional removal
Anuradha| 21
Haritha | 21
Arushi | 22
q)delete Haritha from `d / removal in place
`d
q)d
Anuradha| 21
Arushi | 22
Mani | 21
Removal in place in q is effectively restricted to global tables. Within functions, use functional methods.
Sort list of dictionaries by value¶
>>> lis = [{ "name" : "Nandini", "age" : 20},
... { "name" : "Manjeet", "age" : 20 },
... { "name" : "Nikhil" , "age" : 19 }]
>>>
>>> sorted(lis, key=itemgetter('age', 'name'))
[{'name': 'Nikhil', 'age': 19}, {'name': 'Manjeet', 'age': 20}, {'name': 'Nandini', 'age': 20}]
>>> sorted(lis, key=itemgetter('age'),reverse = True)
[{'name': 'Nandini', 'age': 20}, {'name': 'Manjeet', 'age': 20}, {'name': 'Nikhil', 'age': 19}]
A list of q same-key dictionaries is… a table.
q)show lis:(`name`age!(`Nandini;20); `name`age!(`Manjeet;20); `name`age!(`Nikhil;19))
name age
-----------
Nandini 20
Manjeet 20
Nikhil 19
q)lis iasc lis`age / sort ascending by age
name age
-----------
Nikhil 19
Nandini 20
Manjeet 20
q)lis{x iasc x y}/`name`age / sort by name within age
name age
-----------
Nikhil 19
Manjeet 20
Nandini 20
Merge two dictionaries¶
Using Python 2
def merge(dict1, dict2):
d = {}
d.update(dict1)
d.update(dict2)
return d
>>> d1 = {'a': 10, 'b': 8, 'c': 42}
>>> d2 = {'d': 6, 'c': 4}
>>> merge(d1, d2)
{'a': 10, 'b': 8, 'c': 4, 'd': 6}
or in Python 3
>>> d1 = {'a': 10, 'b': 8, 'c': 42}
>>> d2 = {'d': 6, 'c': 4}
>>> {**d1, **d2}
{'a': 10, 'b': 8, 'c': 4, 'd': 6}
The Join operator (,
) in q has upsert semantics.
q)d1:`a`b`c!10 8 42
q)d2:`d`c!6 4
q)d1,d2
a| 10
b| 8
c| 4
d| 6
Grade calculator¶
grades.py
jack = { "name":"Jack Frost",
"assignment" : [80, 50, 40, 20],
"test" : [75, 75],
"lab" : [78.20, 77.20]
}
james = { "name":"James Potter",
"assignment" : [82, 56, 44, 30],
"test" : [80, 80],
"lab" : [67.90, 78.72]
}
dylan = { "name" : "Dylan Rhodes",
"assignment" : [77, 82, 23, 39],
"test" : [78, 77],
"lab" : [80, 80]
}
jess = { "name" : "Jessica Stone",
"assignment" : [67, 55, 77, 21],
"test" : [40, 50],
"lab" : [69, 44.56]
}
tom = { "name" : "Tom Hanks",
"assignment" : [29, 89, 60, 56],
"test" : [65, 56],
"lab" : [50, 40.6]
}
def get_average(marks):
total_sum = sum(marks)
total_sum = float(total_sum)
return total_sum / len(marks)
def calculate_total_average(students):
assignment = get_average(students["assignment"])
test = get_average(students["test"])
lab = get_average(students["lab"])
# Result based on weightings
return (0.1 * assignment +
0.7 * test + 0.2 * lab)
def assign_letter_grade(score):
if score >= 90: return "A"
elif score >= 80: return "B"
elif score >= 70: return "C"
elif score >= 60: return "D"
else : return "E"
def class_average_is(student_list):
result_list = []
for student in student_list:
stud_avg = calculate_total_average(student)
result_list.append(stud_avg)
return get_average(result_list)
students = [jack, james, dylan, jess, tom]
for i in students :
print(i["name"])
print("=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=")
print("Average marks of %s is : %s " %(i["name"],
calculate_total_average(i)))
print("Letter Grade of %s is : %s" %(i["name"],
assign_letter_grade(calculate_total_average(i))))
print()
class_av = class_average_is(students)
print( "Class Average is %s" %(class_av))
print("Letter Grade of the class is %s "
%(assign_letter_grade(class_av)))
$ python3 grades.py
Jack Frost
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
Average marks of Jack Frost is : 72.79
Letter Grade of Jack Frost is : C
James Potter
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
Average marks of James Potter is : 75.962
Letter Grade of James Potter is : C
Dylan Rhodes
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
Average marks of Dylan Rhodes is : 75.775
Letter Grade of Dylan Rhodes is : C
Jessica Stone
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
Average marks of Jessica Stone is : 48.356
Letter Grade of Jessica Stone is : E
Tom Hanks
=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
Average marks of Tom Hanks is : 57.26
Letter Grade of Tom Hanks is : E
Class Average is 72.79
Letter Grade of the class is C
Median not average
The output above displays the class median score and letter grade, not the average. Oops.
Shorter programs are easier to get right.
grades.q
/ grade calculator
students:flip`name`assignment`test`lab!flip(
(`JackFrost; 80 50 40 20; 75 75; 78.20 77.20);
(`JamesPotter; 82 56 44 30; 80 80; 67.90 78.72);
(`DylanRhodes; 77 82 23 39; 78 77; 80 80);
(`JessicaStone; 67 55 77 21; 40 50; 69 44.56);
(`TomHanks; 29 89 60 56; 65 56; 50 40.6)
)
students[`mark]:sum .1 .7 .2*(avg'')students `assignment`test`lab
lg:{"EDCBA"sum 60 70 80 90<\:x} / letter grade from mark
update letter:lg mark from `students;
show students
"Class average: ",string ca:avg students`mark
"Class letter grade: ",lg ca
q)\l grades.q
name assignment test lab mark letter
-------------------------------------------------------
JackFrost 80 50 40 20 75 75 78.2 77.2 72.79 C
JamesPotter 82 56 44 30 80 80 67.9 78.72 75.962 C
DylanRhodes 77 82 23 39 78 77 80 80 75.775 C
JessicaStone 67 55 77 21 40 50 69 44.56 48.356 E
TomHanks 29 89 60 56 65 56 50 40.6 57.26 E
"Class average: 66.0286"
"Class letter grade: D"
Mirror characters in a string¶
def mirrorChars(s, k):
original = 'abcdefghijklmnopqrstuvwxyz'
reverse = 'zyxwvutsrqponmlkjihgfedcba'
m = dict(zip(original,reverse))
lst = list(s)
ti = range(k-1, len(lst))
for i in ti: lst[i] = m[lst[i]]
return ''.join(lst)
>>> mirrorChars('paradox', 3)
'paizwlc'
mirrorChars:{[s;k]
m:{x!reverse x}.Q.a; / mirror dictionary
ti:(k-1)_ til count s; / target indexes
@[s;ti;m] }
q)mirrorChars["paradox";3]
"paizwlc"
Python and q solutions implement the same strategy:
- write a mirror dictionary
m
- identify the indexes to be targeted
ti
- replace the characters at those indexes with their mirrors
The Python has the further steps of converting the string to a list and back again.
Count frequency¶
>>> lst = ([1, 1, 1, 5, 5, 3, 1, 3, 3, 1, 4, 4, 4, 2, 2, 2, 2])
>>> from collections import Counter
>>> Counter(lst)
Counter({1: 5, 2: 4, 3: 3, 4: 3, 5: 2})
q)lst:1 1 1 5 5 3 1 3 3 1 4 4 4 2 2 2 2
q)count each group lst
1| 5
5| 2
3| 3
4| 3
2| 4
Tuples to dictionary¶
>>> tups = [("akash", 10), ("gaurav", 12), ("anand", 14), ("suraj", 20),
... ("akhil", 25), ("ashish", 30)]
>>> {t[0]:t[1] for t in tups}
{'akash': 10, 'gaurav': 12, 'anand': 14, 'suraj': 20, 'akhil': 25, 'ashish': 30}
q)tups:(("akash";10);("gaurav";12);("anand";14);("suraj";20);("akhil";25);("ashish";30))
q)(!).flip tups
"akash" | 10
"gaurav"| 12
"anand" | 14
"suraj" | 20
"akhil" | 25
"ashish"| 30
Here we flip the tuples to get two lists, which we pass to Apply (.
) as the arguments to Dict (!
).
The heading suggests a more general problem than turning a list of pairs into a dictionary. In q, the general case, with tuples of unspecified length, is handled by keyed tables.