# 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:abc!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:AnuradhaHarithaArushiMani!21 21 22 21

q)delete Mani from d        / functional removal
Haritha | 21
Arushi  | 22

q)delete Haritha from d    / removal in place
d
q)d
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:(nameage!(Nandini;20); nameage!(Manjeet;20); nameage!(Nikhil;19))
name    age
-----------
Nandini 20
Manjeet 20
Nikhil  19
q)lis iasc lisage              / sort ascending by age
name    age
-----------
Nikhil  19
Nandini 20
Manjeet 20

q)lis{x iasc x y}/nameage     / 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:abc!10 8 42
q)d2:dc!6 4

q)d1,d2
a| 10
b| 8
c| 4
d| 6

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)

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)

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"],

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:flipnameassignmenttestlab!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 assignmenttestlab
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 studentsmark
"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.