Skip to content

Instantly share code, notes, and snippets.

@audhiaprilliant
Last active July 28, 2021 15:54
Show Gist options
  • Select an option

  • Save audhiaprilliant/7481dc739f81cc4e74f897c844444eff to your computer and use it in GitHub Desktop.

Select an option

Save audhiaprilliant/7481dc739f81cc4e74f897c844444eff to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "thousand-watson",
"metadata": {},
"source": [
"# Keyboard Typo Corrector"
]
},
{
"cell_type": "markdown",
"id": "missing-scheme",
"metadata": {},
"source": [
"**Reference**\n",
"- Dijkstras algorithm for Shortest path: https://likegeeks.com/python-dijkstras-algorithm/\n",
"- Keyboard layout: https://www.typingpal.com/en/news/what-is-the-difference-between-QWERTY-QWERTZ-and-AZERTY-keyboards\n",
"\n",
"**Finding shortest path**\n",
"- Dijkstra’s algorithm\n",
"- Bellman-Ford algorithm\n",
"- Floyd-Warshall algorithm\n",
"- Johnson’s algorithm"
]
},
{
"cell_type": "markdown",
"id": "micro-corpus",
"metadata": {},
"source": [
"---"
]
},
{
"cell_type": "markdown",
"id": "painted-spectacular",
"metadata": {},
"source": [
"## Import modules"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "verified-facial",
"metadata": {},
"outputs": [],
"source": [
"# Module for collection manipulation\n",
"from collections import defaultdict"
]
},
{
"cell_type": "markdown",
"id": "transparent-junction",
"metadata": {},
"source": [
"## Convert data into graph representation"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "effective-fairy",
"metadata": {},
"outputs": [],
"source": [
"# Dictionary for QWERTY keyboard\n",
"dict_qwerty = {\n",
" 'Q': [['Q', 'W'], ['Q', 'S'], ['Q', 'A']],\n",
" 'A': [['A', 'W'], ['A', 'Q'], ['Q', 'S'], ['A', 'Z'], ['A', 'X']],\n",
" 'Z': [['Z', 'A'], ['Z', 'S'], ['Z', 'X']],\n",
" 'W': [['W', 'Q'], ['W', 'A'], ['W', 'S'], ['W', 'D'], ['W', 'E']],\n",
" 'S': [['S', 'Q'], ['S', 'W'], ['S', 'E'], ['S', 'A'], ['S', 'D'], ['S', 'Z'], ['S', 'X'], ['S', 'C']],\n",
" 'X': [['X', 'Z'], ['X', 'A'], ['X', 'S'], ['X', 'D'], ['X', 'C']],\n",
" 'E': [['E', 'W'], ['E', 'S'], ['E', 'D'], ['E', 'F'], ['E', 'R']],\n",
" 'D': [['D', 'W'], ['D', 'E'], ['D', 'R'], ['D', 'S'], ['D', 'F'], ['D', 'X'], ['D', 'C'], ['D', 'V']],\n",
" 'R': [['R', 'E'], ['R', 'D'], ['R', 'F'], ['R', 'G'], ['R', 'T']],\n",
" 'F': [['F', 'E'], ['F', 'R'], ['F', 'T'], ['F', 'D'], ['F', 'G'], ['F', 'C'], ['F', 'V'], ['F', 'B']],\n",
" 'V': [['V', 'D'], ['V', 'F'], ['V', 'G'], ['V', 'C'], ['V', 'B']],\n",
" 'T': [['T', 'R'], ['T', 'Y'], ['T', 'F'], ['T', 'G'], ['T', 'H']],\n",
" 'G': [['G', 'R'], ['G', 'T'], ['G', 'Y'], ['G', 'F'], ['G', 'H'], ['G', 'V'], ['G', 'B'], ['G', 'N']],\n",
" 'B': [['B', 'F'], ['B', 'G'], ['B', 'H'], ['B', 'V'], ['B', 'N']],\n",
" 'Y': [['Y', 'T'], ['Y', 'U'], ['Y', 'G'], ['Y', 'H'], ['Y', 'J']],\n",
" 'H': [['H', 'T'], ['H', 'Y'], ['H', 'U'], ['H', 'G'], ['H', 'J'], ['H', 'B'], ['H', 'N'], ['H', 'M']],\n",
" 'N': [['N', 'G'], ['N', 'H'], ['N', 'J'], ['N', 'B'], ['N', 'M']],\n",
" 'U': [['U', 'Y'], ['U', 'I'], ['U', 'H'], ['U', 'J'], ['U', 'K']],\n",
" 'J': [['J', 'Y'], ['J', 'U'], ['J', 'I'], ['J', 'H'], ['J', 'K'], ['J', 'N'], ['J', 'M']],\n",
" 'M': [['M', 'H'], ['M', 'J'], ['M', 'K'], ['M', 'N']],\n",
" 'I': [['I', 'U'], ['I', 'O'], ['I', 'J'], ['I', 'K'], ['I', 'L']],\n",
" 'K': [['K', 'U'], ['K', 'I'], ['K', 'O'], ['K', 'J'], ['K', 'L'], ['K', 'M']],\n",
" 'O': [['O', 'I'], ['O', 'P'], ['O', 'K'], ['O', 'L']],\n",
" 'L': [['L', 'I'], ['L', 'O'], ['L', 'P'], ['L', 'K']],\n",
" 'P': [['P', 'O'], ['P', 'L']]\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "significant-request",
"metadata": {},
"outputs": [],
"source": [
"# Get all values from dictionary without distance\n",
"edges_without_distance = []\n",
"for key in dict_qwerty.keys():\n",
" for elem in dict_qwerty[key]:\n",
" edges_without_distance.append(elem)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "municipal-surge",
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"133"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(edges_without_distance)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "caring-strain",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[['Q', 'W'],\n",
" ['Q', 'S'],\n",
" ['Q', 'A'],\n",
" ['A', 'W'],\n",
" ['A', 'Q'],\n",
" ['Q', 'S'],\n",
" ['A', 'Z'],\n",
" ['A', 'X'],\n",
" ['Z', 'A'],\n",
" ['Z', 'S'],\n",
" ['Z', 'X'],\n",
" ['W', 'Q'],\n",
" ['W', 'A'],\n",
" ['W', 'S'],\n",
" ['W', 'D'],\n",
" ['W', 'E'],\n",
" ['S', 'Q'],\n",
" ['S', 'W'],\n",
" ['S', 'E'],\n",
" ['S', 'A'],\n",
" ['S', 'D'],\n",
" ['S', 'Z'],\n",
" ['S', 'X'],\n",
" ['S', 'C'],\n",
" ['X', 'Z'],\n",
" ['X', 'A'],\n",
" ['X', 'S'],\n",
" ['X', 'D'],\n",
" ['X', 'C'],\n",
" ['E', 'W'],\n",
" ['E', 'S'],\n",
" ['E', 'D'],\n",
" ['E', 'F'],\n",
" ['E', 'R'],\n",
" ['D', 'W'],\n",
" ['D', 'E'],\n",
" ['D', 'R'],\n",
" ['D', 'S'],\n",
" ['D', 'F'],\n",
" ['D', 'X'],\n",
" ['D', 'C'],\n",
" ['D', 'V'],\n",
" ['R', 'E'],\n",
" ['R', 'D'],\n",
" ['R', 'F'],\n",
" ['R', 'G'],\n",
" ['R', 'T'],\n",
" ['F', 'E'],\n",
" ['F', 'R'],\n",
" ['F', 'T'],\n",
" ['F', 'D'],\n",
" ['F', 'G'],\n",
" ['F', 'C'],\n",
" ['F', 'V'],\n",
" ['F', 'B'],\n",
" ['V', 'D'],\n",
" ['V', 'F'],\n",
" ['V', 'G'],\n",
" ['V', 'C'],\n",
" ['V', 'B'],\n",
" ['T', 'R'],\n",
" ['T', 'Y'],\n",
" ['T', 'F'],\n",
" ['T', 'G'],\n",
" ['T', 'H'],\n",
" ['G', 'R'],\n",
" ['G', 'T'],\n",
" ['G', 'Y'],\n",
" ['G', 'F'],\n",
" ['G', 'H'],\n",
" ['G', 'V'],\n",
" ['G', 'B'],\n",
" ['G', 'N'],\n",
" ['B', 'F'],\n",
" ['B', 'G'],\n",
" ['B', 'H'],\n",
" ['B', 'V'],\n",
" ['B', 'N'],\n",
" ['Y', 'T'],\n",
" ['Y', 'U'],\n",
" ['Y', 'G'],\n",
" ['Y', 'H'],\n",
" ['Y', 'J'],\n",
" ['H', 'T'],\n",
" ['H', 'Y'],\n",
" ['H', 'U'],\n",
" ['H', 'G'],\n",
" ['H', 'J'],\n",
" ['H', 'B'],\n",
" ['H', 'N'],\n",
" ['H', 'M'],\n",
" ['N', 'G'],\n",
" ['N', 'H'],\n",
" ['N', 'J'],\n",
" ['N', 'B'],\n",
" ['N', 'M'],\n",
" ['U', 'Y'],\n",
" ['U', 'I'],\n",
" ['U', 'H'],\n",
" ['U', 'J'],\n",
" ['U', 'K'],\n",
" ['J', 'Y'],\n",
" ['J', 'U'],\n",
" ['J', 'I'],\n",
" ['J', 'H'],\n",
" ['J', 'K'],\n",
" ['J', 'N'],\n",
" ['J', 'M'],\n",
" ['M', 'H'],\n",
" ['M', 'J'],\n",
" ['M', 'K'],\n",
" ['M', 'N'],\n",
" ['I', 'U'],\n",
" ['I', 'O'],\n",
" ['I', 'J'],\n",
" ['I', 'K'],\n",
" ['I', 'L'],\n",
" ['K', 'U'],\n",
" ['K', 'I'],\n",
" ['K', 'O'],\n",
" ['K', 'J'],\n",
" ['K', 'L'],\n",
" ['K', 'M'],\n",
" ['O', 'I'],\n",
" ['O', 'P'],\n",
" ['O', 'K'],\n",
" ['O', 'L'],\n",
" ['L', 'I'],\n",
" ['L', 'O'],\n",
" ['L', 'P'],\n",
" ['L', 'K'],\n",
" ['P', 'O'],\n",
" ['P', 'L']]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"edges_without_distance"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "declared-aberdeen",
"metadata": {},
"outputs": [],
"source": [
"# Get all values from dictionary with distance\n",
"edges_with_distance = []\n",
"for key in dict_qwerty.keys():\n",
" for elem in dict_qwerty[key]:\n",
" new_elem = elem + [1]\n",
" edges_with_distance.append(new_elem)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "impressed-ballet",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[['Q', 'W', 1],\n",
" ['Q', 'S', 1],\n",
" ['Q', 'A', 1],\n",
" ['A', 'W', 1],\n",
" ['A', 'Q', 1],\n",
" ['Q', 'S', 1],\n",
" ['A', 'Z', 1],\n",
" ['A', 'X', 1],\n",
" ['Z', 'A', 1],\n",
" ['Z', 'S', 1],\n",
" ['Z', 'X', 1],\n",
" ['W', 'Q', 1],\n",
" ['W', 'A', 1],\n",
" ['W', 'S', 1],\n",
" ['W', 'D', 1],\n",
" ['W', 'E', 1],\n",
" ['S', 'Q', 1],\n",
" ['S', 'W', 1],\n",
" ['S', 'E', 1],\n",
" ['S', 'A', 1],\n",
" ['S', 'D', 1],\n",
" ['S', 'Z', 1],\n",
" ['S', 'X', 1],\n",
" ['S', 'C', 1],\n",
" ['X', 'Z', 1],\n",
" ['X', 'A', 1],\n",
" ['X', 'S', 1],\n",
" ['X', 'D', 1],\n",
" ['X', 'C', 1],\n",
" ['E', 'W', 1],\n",
" ['E', 'S', 1],\n",
" ['E', 'D', 1],\n",
" ['E', 'F', 1],\n",
" ['E', 'R', 1],\n",
" ['D', 'W', 1],\n",
" ['D', 'E', 1],\n",
" ['D', 'R', 1],\n",
" ['D', 'S', 1],\n",
" ['D', 'F', 1],\n",
" ['D', 'X', 1],\n",
" ['D', 'C', 1],\n",
" ['D', 'V', 1],\n",
" ['R', 'E', 1],\n",
" ['R', 'D', 1],\n",
" ['R', 'F', 1],\n",
" ['R', 'G', 1],\n",
" ['R', 'T', 1],\n",
" ['F', 'E', 1],\n",
" ['F', 'R', 1],\n",
" ['F', 'T', 1],\n",
" ['F', 'D', 1],\n",
" ['F', 'G', 1],\n",
" ['F', 'C', 1],\n",
" ['F', 'V', 1],\n",
" ['F', 'B', 1],\n",
" ['V', 'D', 1],\n",
" ['V', 'F', 1],\n",
" ['V', 'G', 1],\n",
" ['V', 'C', 1],\n",
" ['V', 'B', 1],\n",
" ['T', 'R', 1],\n",
" ['T', 'Y', 1],\n",
" ['T', 'F', 1],\n",
" ['T', 'G', 1],\n",
" ['T', 'H', 1],\n",
" ['G', 'R', 1],\n",
" ['G', 'T', 1],\n",
" ['G', 'Y', 1],\n",
" ['G', 'F', 1],\n",
" ['G', 'H', 1],\n",
" ['G', 'V', 1],\n",
" ['G', 'B', 1],\n",
" ['G', 'N', 1],\n",
" ['B', 'F', 1],\n",
" ['B', 'G', 1],\n",
" ['B', 'H', 1],\n",
" ['B', 'V', 1],\n",
" ['B', 'N', 1],\n",
" ['Y', 'T', 1],\n",
" ['Y', 'U', 1],\n",
" ['Y', 'G', 1],\n",
" ['Y', 'H', 1],\n",
" ['Y', 'J', 1],\n",
" ['H', 'T', 1],\n",
" ['H', 'Y', 1],\n",
" ['H', 'U', 1],\n",
" ['H', 'G', 1],\n",
" ['H', 'J', 1],\n",
" ['H', 'B', 1],\n",
" ['H', 'N', 1],\n",
" ['H', 'M', 1],\n",
" ['N', 'G', 1],\n",
" ['N', 'H', 1],\n",
" ['N', 'J', 1],\n",
" ['N', 'B', 1],\n",
" ['N', 'M', 1],\n",
" ['U', 'Y', 1],\n",
" ['U', 'I', 1],\n",
" ['U', 'H', 1],\n",
" ['U', 'J', 1],\n",
" ['U', 'K', 1],\n",
" ['J', 'Y', 1],\n",
" ['J', 'U', 1],\n",
" ['J', 'I', 1],\n",
" ['J', 'H', 1],\n",
" ['J', 'K', 1],\n",
" ['J', 'N', 1],\n",
" ['J', 'M', 1],\n",
" ['M', 'H', 1],\n",
" ['M', 'J', 1],\n",
" ['M', 'K', 1],\n",
" ['M', 'N', 1],\n",
" ['I', 'U', 1],\n",
" ['I', 'O', 1],\n",
" ['I', 'J', 1],\n",
" ['I', 'K', 1],\n",
" ['I', 'L', 1],\n",
" ['K', 'U', 1],\n",
" ['K', 'I', 1],\n",
" ['K', 'O', 1],\n",
" ['K', 'J', 1],\n",
" ['K', 'L', 1],\n",
" ['K', 'M', 1],\n",
" ['O', 'I', 1],\n",
" ['O', 'P', 1],\n",
" ['O', 'K', 1],\n",
" ['O', 'L', 1],\n",
" ['L', 'I', 1],\n",
" ['L', 'O', 1],\n",
" ['L', 'P', 1],\n",
" ['L', 'K', 1],\n",
" ['P', 'O', 1],\n",
" ['P', 'L', 1]]"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"edges_with_distance"
]
},
{
"cell_type": "markdown",
"id": "outside-container",
"metadata": {},
"source": [
"## Function for shortest pathfinding"
]
},
{
"cell_type": "markdown",
"id": "spoken-process",
"metadata": {},
"source": [
"**Input**\n",
"- Edges\n",
"- Starting point\n",
"- Destination point\n",
"\n",
"**Output**\n",
"- Shortest path\n",
"- Distance\n",
"\n",
"**Source**\n",
"- https://gist.github.com/dingran/b827b65a252000e25d818ba3520242e1"
]
},
{
"cell_type": "markdown",
"id": "assumed-distribution",
"metadata": {},
"source": [
"**Functions**"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "finished-craps",
"metadata": {},
"outputs": [],
"source": [
"# Build the graph\n",
"def build_graph(edge_list):\n",
" graph = defaultdict(list)\n",
" seen_edges = defaultdict(int)\n",
" for src, dst, weight in edge_list:\n",
" seen_edges[(src, dst, weight)] += 1\n",
" if seen_edges[(src, dst, weight)] > 1:\n",
" continue\n",
" graph[src].append((dst, weight))\n",
" graph[dst].append((src, weight))\n",
" return graph\n",
"\n",
"# Dijkstra algorithm\n",
"def dijkstra(graph, src, dst = None):\n",
" nodes = []\n",
" for n in graph:\n",
" nodes.append(n)\n",
" nodes += [x[0] for x in graph[n]]\n",
"\n",
" q = set(nodes)\n",
" nodes = list(q)\n",
" dist = dict()\n",
" prev = dict()\n",
" for n in nodes:\n",
" dist[n] = float('inf')\n",
" prev[n] = None\n",
"\n",
" dist[src] = 0\n",
"\n",
" while q:\n",
" u = min(q, key=dist.get)\n",
" q.remove(u)\n",
"\n",
" if dst is not None and u == dst:\n",
" return dist[dst], prev\n",
"\n",
" for v, w in graph.get(u, ()):\n",
" alt = dist[u] + w\n",
" if alt < dist[v]:\n",
" dist[v] = alt\n",
" prev[v] = u\n",
"\n",
" return dist, prev\n",
"\n",
"# Find shortest path\n",
"def find_path(pr, node):\n",
" p = []\n",
" while node is not None:\n",
" p.append(node)\n",
" node = pr[node]\n",
" return p[::-1]"
]
},
{
"cell_type": "markdown",
"id": "toxic-capability",
"metadata": {},
"source": [
"**Theoretical implementation**"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "included-gambling",
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"# List of edges\n",
"edges = [\n",
" ('A', 'B', 7),\n",
" ('A', 'D', 5),\n",
" ('B', 'C', 8),\n",
" ('B', 'D', 9),\n",
" ('B', 'E', 7),\n",
" ('C', 'E', 5),\n",
" ('D', 'E', 15),\n",
" ('D', 'F', 6),\n",
" ('E', 'F', 8),\n",
" ('E', 'G', 9),\n",
" ('F', 'G', 11)\n",
"]\n",
"\n",
"# Create a graph\n",
"g = build_graph(edges)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "rural-behalf",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--- Single source, single destination ---\n",
"A -> E: distance = 14, path = ['A', 'B', 'E']\n",
"F -> G: distance = 11, path = ['F', 'G']\n"
]
}
],
"source": [
"# Single source, single destination\n",
"print('--- Single source, single destination ---')\n",
"d, prev = dijkstra(g, 'A', 'E')\n",
"path = find_path(prev, 'E')\n",
"print('A -> E: distance = {}, path = {}'.format(d, path))\n",
"\n",
"d, prev = dijkstra(g, 'F', 'G')\n",
"path = find_path(prev, 'G')\n",
"print('F -> G: distance = {}, path = {}'.format(d, path))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "embedded-radius",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--- Single source, all destinations ---\n",
"A -> E: distance = 14, path = ['A', 'B', 'E']\n",
"A -> F: distance = 11, path = ['A', 'D', 'F']\n",
"A -> A: distance = 0, path = ['A']\n",
"A -> B: distance = 7, path = ['A', 'B']\n",
"A -> D: distance = 5, path = ['A', 'D']\n",
"A -> G: distance = 22, path = ['A', 'D', 'F', 'G']\n",
"A -> C: distance = 15, path = ['A', 'B', 'C']\n"
]
}
],
"source": [
"# Single source, all destinations\n",
"print('--- Single source, all destinations ---')\n",
"ds, prev = dijkstra(g, 'A')\n",
"for k in ds:\n",
" path = find_path(prev, k)\n",
" print('A -> {}: distance = {}, path = {}'.format(k, ds[k], path))"
]
},
{
"cell_type": "markdown",
"id": "rational-lingerie",
"metadata": {},
"source": [
"**Real implementation on keyboard**"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "sensitive-cooperation",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"defaultdict(list,\n",
" {'Q': [('W', 1), ('S', 1), ('A', 1), ('A', 1), ('W', 1), ('S', 1)],\n",
" 'W': [('Q', 1),\n",
" ('A', 1),\n",
" ('Q', 1),\n",
" ('A', 1),\n",
" ('S', 1),\n",
" ('D', 1),\n",
" ('E', 1),\n",
" ('S', 1),\n",
" ('E', 1),\n",
" ('D', 1)],\n",
" 'S': [('Q', 1),\n",
" ('Z', 1),\n",
" ('W', 1),\n",
" ('Q', 1),\n",
" ('W', 1),\n",
" ('E', 1),\n",
" ('A', 1),\n",
" ('D', 1),\n",
" ('Z', 1),\n",
" ('X', 1),\n",
" ('C', 1),\n",
" ('X', 1),\n",
" ('E', 1),\n",
" ('D', 1)],\n",
" 'A': [('Q', 1),\n",
" ('W', 1),\n",
" ('Q', 1),\n",
" ('Z', 1),\n",
" ('X', 1),\n",
" ('Z', 1),\n",
" ('W', 1),\n",
" ('S', 1),\n",
" ('X', 1)],\n",
" 'Z': [('A', 1), ('A', 1), ('S', 1), ('X', 1), ('S', 1), ('X', 1)],\n",
" 'X': [('A', 1),\n",
" ('Z', 1),\n",
" ('S', 1),\n",
" ('Z', 1),\n",
" ('A', 1),\n",
" ('S', 1),\n",
" ('D', 1),\n",
" ('C', 1),\n",
" ('D', 1)],\n",
" 'D': [('W', 1),\n",
" ('S', 1),\n",
" ('X', 1),\n",
" ('E', 1),\n",
" ('W', 1),\n",
" ('E', 1),\n",
" ('R', 1),\n",
" ('S', 1),\n",
" ('F', 1),\n",
" ('X', 1),\n",
" ('C', 1),\n",
" ('V', 1),\n",
" ('R', 1),\n",
" ('F', 1),\n",
" ('V', 1)],\n",
" 'E': [('W', 1),\n",
" ('S', 1),\n",
" ('W', 1),\n",
" ('S', 1),\n",
" ('D', 1),\n",
" ('F', 1),\n",
" ('R', 1),\n",
" ('D', 1),\n",
" ('R', 1),\n",
" ('F', 1)],\n",
" 'C': [('S', 1), ('X', 1), ('D', 1), ('F', 1), ('V', 1)],\n",
" 'F': [('E', 1),\n",
" ('D', 1),\n",
" ('R', 1),\n",
" ('E', 1),\n",
" ('R', 1),\n",
" ('T', 1),\n",
" ('D', 1),\n",
" ('G', 1),\n",
" ('C', 1),\n",
" ('V', 1),\n",
" ('B', 1),\n",
" ('V', 1),\n",
" ('T', 1),\n",
" ('G', 1),\n",
" ('B', 1)],\n",
" 'R': [('E', 1),\n",
" ('D', 1),\n",
" ('E', 1),\n",
" ('D', 1),\n",
" ('F', 1),\n",
" ('G', 1),\n",
" ('T', 1),\n",
" ('F', 1),\n",
" ('T', 1),\n",
" ('G', 1)],\n",
" 'V': [('D', 1),\n",
" ('F', 1),\n",
" ('D', 1),\n",
" ('F', 1),\n",
" ('G', 1),\n",
" ('C', 1),\n",
" ('B', 1),\n",
" ('G', 1),\n",
" ('B', 1)],\n",
" 'G': [('R', 1),\n",
" ('F', 1),\n",
" ('V', 1),\n",
" ('T', 1),\n",
" ('R', 1),\n",
" ('T', 1),\n",
" ('Y', 1),\n",
" ('F', 1),\n",
" ('H', 1),\n",
" ('V', 1),\n",
" ('B', 1),\n",
" ('N', 1),\n",
" ('B', 1),\n",
" ('Y', 1),\n",
" ('H', 1),\n",
" ('N', 1)],\n",
" 'T': [('R', 1),\n",
" ('F', 1),\n",
" ('R', 1),\n",
" ('Y', 1),\n",
" ('F', 1),\n",
" ('G', 1),\n",
" ('H', 1),\n",
" ('G', 1),\n",
" ('Y', 1),\n",
" ('H', 1)],\n",
" 'B': [('F', 1),\n",
" ('V', 1),\n",
" ('G', 1),\n",
" ('F', 1),\n",
" ('G', 1),\n",
" ('H', 1),\n",
" ('V', 1),\n",
" ('N', 1),\n",
" ('H', 1),\n",
" ('N', 1)],\n",
" 'Y': [('T', 1),\n",
" ('G', 1),\n",
" ('T', 1),\n",
" ('U', 1),\n",
" ('G', 1),\n",
" ('H', 1),\n",
" ('J', 1),\n",
" ('H', 1),\n",
" ('U', 1),\n",
" ('J', 1)],\n",
" 'H': [('T', 1),\n",
" ('G', 1),\n",
" ('B', 1),\n",
" ('Y', 1),\n",
" ('T', 1),\n",
" ('Y', 1),\n",
" ('U', 1),\n",
" ('G', 1),\n",
" ('J', 1),\n",
" ('B', 1),\n",
" ('N', 1),\n",
" ('M', 1),\n",
" ('N', 1),\n",
" ('U', 1),\n",
" ('J', 1),\n",
" ('M', 1)],\n",
" 'N': [('G', 1),\n",
" ('B', 1),\n",
" ('H', 1),\n",
" ('G', 1),\n",
" ('H', 1),\n",
" ('J', 1),\n",
" ('B', 1),\n",
" ('M', 1),\n",
" ('J', 1),\n",
" ('M', 1)],\n",
" 'U': [('Y', 1),\n",
" ('H', 1),\n",
" ('Y', 1),\n",
" ('I', 1),\n",
" ('H', 1),\n",
" ('J', 1),\n",
" ('K', 1),\n",
" ('J', 1),\n",
" ('I', 1),\n",
" ('K', 1)],\n",
" 'J': [('Y', 1),\n",
" ('H', 1),\n",
" ('N', 1),\n",
" ('U', 1),\n",
" ('Y', 1),\n",
" ('U', 1),\n",
" ('I', 1),\n",
" ('H', 1),\n",
" ('K', 1),\n",
" ('N', 1),\n",
" ('M', 1),\n",
" ('M', 1),\n",
" ('I', 1),\n",
" ('K', 1)],\n",
" 'M': [('H', 1),\n",
" ('N', 1),\n",
" ('J', 1),\n",
" ('H', 1),\n",
" ('J', 1),\n",
" ('K', 1),\n",
" ('N', 1),\n",
" ('K', 1)],\n",
" 'I': [('U', 1),\n",
" ('J', 1),\n",
" ('U', 1),\n",
" ('O', 1),\n",
" ('J', 1),\n",
" ('K', 1),\n",
" ('L', 1),\n",
" ('K', 1),\n",
" ('O', 1),\n",
" ('L', 1)],\n",
" 'K': [('U', 1),\n",
" ('J', 1),\n",
" ('M', 1),\n",
" ('I', 1),\n",
" ('U', 1),\n",
" ('I', 1),\n",
" ('O', 1),\n",
" ('J', 1),\n",
" ('L', 1),\n",
" ('M', 1),\n",
" ('O', 1),\n",
" ('L', 1)],\n",
" 'O': [('I', 1),\n",
" ('K', 1),\n",
" ('I', 1),\n",
" ('P', 1),\n",
" ('K', 1),\n",
" ('L', 1),\n",
" ('L', 1),\n",
" ('P', 1)],\n",
" 'L': [('I', 1),\n",
" ('K', 1),\n",
" ('O', 1),\n",
" ('I', 1),\n",
" ('O', 1),\n",
" ('P', 1),\n",
" ('K', 1),\n",
" ('P', 1)],\n",
" 'P': [('O', 1), ('L', 1), ('O', 1), ('L', 1)]})"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"graph = build_graph(edges_with_distance)\n",
"graph"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "rising-matthew",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"A -> E: distance = 2, path = ['A', 'S', 'E']\n"
]
}
],
"source": [
"d, prev = dijkstra(graph, 'A', 'E')\n",
"path = find_path(prev, 'E')\n",
"print('A -> E: distance = {}, path = {}'.format(d, path))"
]
},
{
"cell_type": "markdown",
"id": "medical-stupid",
"metadata": {},
"source": [
"## Function for string comparison"
]
},
{
"cell_type": "markdown",
"id": "representative-princess",
"metadata": {},
"source": [
"**Input**\n",
"- First string\n",
"- Second string\n",
"\n",
"**Output**\n",
"- List of position"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "leading-blake",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[1]"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"s1 = 'WATCH'\n",
"s2 = 'WITCH'\n",
"[i for i in range(len(s1)) if s1[i] != s2[i]]"
]
},
{
"cell_type": "markdown",
"id": "objective-angel",
"metadata": {},
"source": [
"## Core functions"
]
},
{
"cell_type": "markdown",
"id": "prepared-signature",
"metadata": {},
"source": [
"**Input**\n",
"- Typo string\n",
"- List of candidate strings\n",
"\n",
"**Output**\n",
"- Dictionary that contains string and distance"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "qualified-petite",
"metadata": {},
"outputs": [],
"source": [
"def keyboard_corrector(graph, typo, strings):\n",
" # Dictionary of distance\n",
" dic_dist = {i:0 for i in strings}\n",
" # Calculate the distance\n",
" for string in strings:\n",
" try:\n",
" index = [i for i in range(len(typo)) if typo[i] != string[i]]\n",
" distance = 0\n",
" for i in index:\n",
" d, prev = dijkstra(graph = graph, src = typo[i], dst = string[i])\n",
" distance += d\n",
" dic_dist.update({string: distance})\n",
" except:\n",
" pass\n",
" return dic_dist"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "knowing-awareness",
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"{'WATCH': 2, 'WITCH': 5}"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"keyboard_corrector(graph = graph, typo = 'WETCH', strings = ['WATCH', 'WITCH'])"
]
},
{
"cell_type": "markdown",
"id": "returning-supplier",
"metadata": {},
"source": [
"---"
]
},
{
"cell_type": "markdown",
"id": "double-raleigh",
"metadata": {},
"source": [
"## Graph representation"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "several-humidity",
"metadata": {},
"outputs": [],
"source": [
"# Module for network analysis\n",
"import networkx as nx\n",
"# Module for data viz\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "illegal-binary",
"metadata": {},
"outputs": [],
"source": [
"# Dictionary for QWERTY keyboard\n",
"dict_sample = {\n",
" 'A': [['A', 'B', 2], ['A', 'C', 3], ['A', 'D', 1]],\n",
" 'B': [['B', 'C', 2], ['B', 'E', 3]],\n",
" 'C': [['C', 'E', 1]],\n",
" 'D': [['D', 'E', 5]]\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "vocal-skill",
"metadata": {},
"outputs": [],
"source": [
"# Get all values from dictionary without distance\n",
"edges_sample = []\n",
"for key in dict_sample.keys():\n",
" for elem in dict_sample[key]:\n",
" edges_sample.append(elem)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "sufficient-woman",
"metadata": {},
"outputs": [],
"source": [
"# Represent it to graph\n",
"graph_with_distance = defaultdict(dict)\n",
"for row in edges_sample:\n",
" graph_with_distance[row[0]][row[1]] = row[2]\n",
" graph_with_distance[row[1]][row[0]] = row[2]"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "reliable-circuit",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"defaultdict(dict,\n",
" {'A': {'B': 2, 'C': 3, 'D': 1},\n",
" 'B': {'A': 2, 'C': 2, 'E': 3},\n",
" 'C': {'A': 3, 'B': 2, 'E': 1},\n",
" 'D': {'A': 1, 'E': 5},\n",
" 'E': {'B': 3, 'C': 1, 'D': 5}})"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"graph_with_distance"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "located-nature",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x432 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.figure(figsize = (6, 6))\n",
"# 1. Create the graph\n",
"g = nx.from_dict_of_lists(graph_with_distance)\n",
"# 2. Create a layout for our nodes \n",
"layout = nx.spring_layout(g, iterations = 50)\n",
"nx.draw(g)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment