Problem 1 done
authorNeil Smith <neil.git@njae.me.uk>
Mon, 15 May 2017 15:54:59 +0000 (16:54 +0100)
committerNeil Smith <neil.git@njae.me.uk>
Mon, 15 May 2017 15:54:59 +0000 (16:54 +0100)
01-ticket-prices/01-holidays.txt [new file with mode: 0644]
01-ticket-prices/ticket-pricing-generator.ipynb [new file with mode: 0644]
01-ticket-prices/ticket-pricing-solution.ipynb [new file with mode: 0644]

diff --git a/01-ticket-prices/01-holidays.txt b/01-ticket-prices/01-holidays.txt
new file mode 100644 (file)
index 0000000..f0f2f9b
--- /dev/null
@@ -0,0 +1,124 @@
+5f12ce1b86 1192 Sukhumi 14
+0279c8a91b 1008 Estacada 14
+1faea40e9c 1085 Tambon-Pa-Fa 14
+f421c9db0e 1056 Giessenmestia 10
+4d0ae38b17 1173 Mamula 7
+a61861c0ac 1692 Mamula 21
+8917807a68 1364 Parowan 7
+dc16c9b87f 1118 Karlukovo 21
+9e074d106c 887 Hajnowski 7
+25b1f581cf 1350 Tambon-Pa-Fa 14
+18568253ed 1368 Grimsey-Island 21
+5ca507289d 1476 Almaty 21
+90450d21f6 734 Karlukovo 3
+6bf2d26963 945 Sofia 7
+f13de9792c 1258 Aalborg 10
+4c3bd41774 1583 Holmegaard 21
+a211ae5b39 1400 Tubakuba 14
+1ee88b0301 1319 Mamula 14
+908ab2a57b 1394 Gorongosa 14
+7ad1ff45a7 1360 Tubakuba 14
+05949506f4 1599 Nullarbor 14
+5c8ae5d69b 1081 Giessenmestia 14
+93bb91f174 1027 Zhangye-Shi 10
+c1cce289bb 1048 Zhangye-Shi 14
+07ba9b25bb 1317 Mora 3
+557495ff48 1245 Brorfelde 14
+4d91320955 1231 Nordkapp 21
+c3d1a965bf 1564 Zhangye-Shi 14
+905044f0db 1231 Zhangye-Shi 14
+d8c29f025b 850 Uzupis 7
+7d21173587 827 Mamula 21
+7b61f62563 1059 Gorongosa 14
+418c819924 1592 Hajnowski 14
+39ba2e545f 1153 Giessenmestia 14
+a88bcde08f 1200 Geoje-Si 21
+ba97dce538 1334 Luoyang 10
+bfedf47e75 1411 Tambon-Pa-Fa 14
+c75972736e 1360 Tambon-Pa-Fa 10
+a627eacf02 1071 Hajnowski 14
+e5fd4f07f0 1722 Estacada 14
+ecedd5dec7 1298 Holmegaard 21
+82a6d39daf 1304 Hajnowski 14
+df88afc558 1002 Stonington-Island 21
+adfcc87811 1291 Uzupis 10
+ab7c401708 1088 Jayuya 14
+4338ffb0c8 1508 Gorongosa 7
+19137c9d63 1147 Aalborg 21
+e3c8a3457a 938 Sofia 14
+9e17759004 873 Brorfelde 10
+949147682b 1708 Tambon-Pa-Fa 14
+cd8a9e25a5 1331 Parowan 21
+49422ce165 966 Ijsseloog 21
+083f95c140 1277 Stonington-Island 7
+6b0687b1d5 1857 Mora 7
+011a8d05a9 1502 Parowan 21
+905e3adc44 1020 Giessenmestia 7
+dd90450a55 1099 Morgantown 7
+558e37a9cb 1570 Lemnos 7
+adfeed7f5b 930 Luoyang 14
+5b55438fd6 1367 Almaty 10
+d6dbecc2c1 653 Jayuya 21
+c824920d19 916 Giessenmestia 7
+f3e75eb80d 1315 Uzupis 14
+f5b0fa5b52 1351 Mora 21
+1b838183cb 1204 Mamula 14
+d123aee4db 1325 Sofia 7
+d4c5260a30 1238 Brorfelde 7
+15dbab77d7 1124 Nullarbor 21
+4224689a18 1016 Sukhumi 14
+f9dbdcceb5 671 Gorongosa 3
+0cf6e1dcda 1522 Karlukovo 7
+e24cd566b5 1264 Lemnos 7
+f006291b5d 1395 Tubakuba 14
+616b33a8eb 1010 Hajnowski 21
+cc7c78b4d5 828 Tambon-Pa-Fa 14
+748933a4a8 1261 Luoyang 14
+3730f51e7a 1425 Grimsey-Island 3
+0a1786b80e 1336 Brorfelde 14
+7834d83383 1220 Morgantown 14
+921d50e71f 1193 Lemnos 21
+81fc28b097 1224 Lemnos 3
+71271e63c2 936 Morgantown 10
+13272fc146 1063 Zhangye-Shi 10
+999a111ce6 1626 Morgantown 7
+1e6696144b 986 Nullarbor 7
+ea8b6ab428 1256 Nordkapp 3
+f2f4aa7f7f 1223 Lemnos 21
+3b75ed4e29 1483 Holmegaard 14
+227468b611 1280 Grimsey-Island 3
+6316268a67 1240 Holmegaard 14
+ace0751a7e 943 Puente-Laguna-Garzonkuala-Penyu 3
+251b0a29b5 1064 Morgantown 7
+08e358a1a5 1302 Giessenmestia 7
+c4e4b32b01 1117 Grimsey-Island 7
+8b45e786d7 1491 Tubakuba 14
+305c933269 922 Puente-Laguna-Garzonkuala-Penyu 14
+05dc1935d7 1187 Lemnos 21
+31283b3453 794 Jayuya 21
+b08811d0dd 785 Stonington-Island 14
+8108742c66 1137 Jayuya 21
+23a0fefaaa 1129 Tambon-Pa-Fa 14
+0172041cc4 1398 Nullarbor 3
+101f85c2a2 1240 Giessenmestia 21
+e62b71d07b 1121 Aalborg 14
+087a0e8722 1244 Parowan 14
+d3a9a562a0 1252 Giessenmestia 3
+ecddeec9a6 1275 Brorfelde 7
+705d831a04 1411 Almaty 3
+2ed3627cba 1185 Sukhumi 21
+659db7f4ad 1324 Tambon-Pa-Fa 3
+204e527a4b 1465 Giessenmestia 21
+ddb845b71a 1225 Uzupis 7
+ea29fb1ec3 1321 Sukhumi 14
+61d9efb897 1071 Aalborg 14
+e32c91ca86 1130 Puente-Laguna-Garzonkuala-Penyu 14
+164b06af74 1188 Hajnowski 21
+3274507344 1099 Brorfelde 7
+bd18df3cc1 1446 Jayuya 3
+971a59b616 967 Nullarbor 7
+cb3169c441 1132 Almaty 7
+d8ab39ff18 1504 Karlukovo 21
+ad350fa7f1 1373 Geoje-Si 7
+660febfb76 1157 Sukhumi 14
+ec8149cba9 1197 Hajnowski 21
diff --git a/01-ticket-prices/ticket-pricing-generator.ipynb b/01-ticket-prices/ticket-pricing-generator.ipynb
new file mode 100644 (file)
index 0000000..3d591fd
--- /dev/null
@@ -0,0 +1,529 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 45,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import random\n",
+    "import re\n",
+    "import uuid"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def cap_after_hyphen(string):\n",
+    "    return re.sub(r'\\-(?P<first>[a-z])', \n",
+    "                  lambda m: '-' + m.group('first').upper(), \n",
+    "                  string)    "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['Aalborg',\n",
+       " 'Nullarbor',\n",
+       " 'Morgantown',\n",
+       " 'Estacada',\n",
+       " 'Almaty',\n",
+       " 'Tambon-Pa-Fa',\n",
+       " 'Lemnos',\n",
+       " 'Sofia',\n",
+       " 'Puente-Laguna-Garzonkuala-Penyu',\n",
+       " 'Hajnowski',\n",
+       " 'Karlukovo',\n",
+       " 'Mamula',\n",
+       " 'Stonington-Island',\n",
+       " 'Grimsey-Island',\n",
+       " 'Uzupis',\n",
+       " 'Sukhumi',\n",
+       " 'Ijsseloog',\n",
+       " 'Giessenmestia',\n",
+       " 'Nordkapp',\n",
+       " 'Gorongosa',\n",
+       " 'Brorfelde',\n",
+       " 'Parowan',\n",
+       " 'Tubakuba',\n",
+       " 'Geoje-Si',\n",
+       " 'Mora',\n",
+       " 'Holmegaard',\n",
+       " 'Jayuya',\n",
+       " 'Zhangye-Shi',\n",
+       " 'Luoyang']"
+      ]
+     },
+     "execution_count": 20,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "destination_names = ('Aalborg Nullarbor MORGANTOWN ESTACADA ALMATY TAMBON-PA-FA Lemnos Sofia Puente-Laguna-Garzon' +\n",
+    "'KUALA-PENYU HAJNOWSKI KARLUKOVO Mamula STONINGTON-ISLAND Grimsey-Island Uzupis SUKHUMI IJsseloog GIESSEN' +\n",
+    "'MESTIA NORDKAPP GORONGOSA Brorfelde PAROWAN Tubakuba GEOJE-SI MORA HOLMEGAARD JAYUYA ZHANGYE-SHI LUOYANG')\n",
+    "destination_names = destination_names.lower().split()\n",
+    "destination_names = [n[0].upper() + n[1:] for n in destination_names]\n",
+    "destination_names = [cap_after_hyphen(n) for n in destination_names]\n",
+    "\n",
+    "destination_names"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 39,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'Aalborg': 1,\n",
+       " 'Almaty': 1,\n",
+       " 'Brorfelde': 1,\n",
+       " 'Estacada': 1,\n",
+       " 'Geoje-Si': 1,\n",
+       " 'Giessenmestia': 1,\n",
+       " 'Gorongosa': 1,\n",
+       " 'Grimsey-Island': 1,\n",
+       " 'Hajnowski': 1,\n",
+       " 'Holmegaard': 1,\n",
+       " 'Ijsseloog': 1,\n",
+       " 'Jayuya': 1,\n",
+       " 'Karlukovo': 1,\n",
+       " 'Lemnos': 1,\n",
+       " 'Luoyang': 1,\n",
+       " 'Mamula': 1,\n",
+       " 'Mora': 1,\n",
+       " 'Morgantown': 1,\n",
+       " 'Nordkapp': 1,\n",
+       " 'Nullarbor': 1,\n",
+       " 'Parowan': 1,\n",
+       " 'Puente-Laguna-Garzonkuala-Penyu': 1,\n",
+       " 'Sofia': 1,\n",
+       " 'Stonington-Island': 1,\n",
+       " 'Sukhumi': 1,\n",
+       " 'Tambon-Pa-Fa': 1,\n",
+       " 'Tubakuba': 1,\n",
+       " 'Uzupis': 1,\n",
+       " 'Zhangye-Shi': 1}"
+      ]
+     },
+     "execution_count": 39,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "destination_scores = {n: 1 for n in destination_names}\n",
+    "destination_scores"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 40,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'Aalborg': 1,\n",
+       " 'Almaty': 2.0,\n",
+       " 'Brorfelde': 0.9,\n",
+       " 'Estacada': 0.4,\n",
+       " 'Geoje-Si': 1,\n",
+       " 'Giessenmestia': 1,\n",
+       " 'Gorongosa': 1,\n",
+       " 'Grimsey-Island': 1,\n",
+       " 'Hajnowski': 1,\n",
+       " 'Holmegaard': 1,\n",
+       " 'Ijsseloog': 1,\n",
+       " 'Jayuya': 0.6,\n",
+       " 'Karlukovo': 2.2,\n",
+       " 'Lemnos': 1,\n",
+       " 'Luoyang': 1,\n",
+       " 'Mamula': 1,\n",
+       " 'Mora': 1,\n",
+       " 'Morgantown': 2.9,\n",
+       " 'Nordkapp': 1.5,\n",
+       " 'Nullarbor': 2.2,\n",
+       " 'Parowan': 1,\n",
+       " 'Puente-Laguna-Garzonkuala-Penyu': 0.4,\n",
+       " 'Sofia': 1,\n",
+       " 'Stonington-Island': 1,\n",
+       " 'Sukhumi': 1,\n",
+       " 'Tambon-Pa-Fa': 1,\n",
+       " 'Tubakuba': 1,\n",
+       " 'Uzupis': 0.9,\n",
+       " 'Zhangye-Shi': 1}"
+      ]
+     },
+     "execution_count": 40,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "adjust = random.sample(destination_names, 10)\n",
+    "inc_names = adjust[:5]\n",
+    "dec_names = adjust[5:]\n",
+    "for n in inc_names:\n",
+    "    destination_scores[n] = float(random.randint(11, 30)) / 10\n",
+    "for n in dec_names:\n",
+    "    destination_scores[n] = float(random.randint(3, 9)) / 10 \n",
+    "destination_scores"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 42,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "destination_scores = {'Aalborg': 1, 'Almaty': 2.0, 'Brorfelde': 0.9, 'Estacada': 0.4, 'Geoje-Si': 1,\n",
+    " 'Giessenmestia': 1, 'Gorongosa': 1, 'Grimsey-Island': 1, 'Hajnowski': 1, 'Holmegaard': 1, 'Ijsseloog': 1,\n",
+    " 'Jayuya': 0.6, 'Karlukovo': 2.2, 'Lemnos': 1, 'Luoyang': 1, 'Mamula': 1, 'Mora': 1, 'Morgantown': 2.9,\n",
+    " 'Nordkapp': 1.5, 'Nullarbor': 2.2, 'Parowan': 1, 'Puente-Laguna-Garzonkuala-Penyu': 0.4, 'Sofia': 1,\n",
+    " 'Stonington-Island': 1, 'Sukhumi': 1, 'Tambon-Pa-Fa': 1, 'Tubakuba': 1, 'Uzupis': 0.9, 'Zhangye-Shi': 1}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 66,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "destination_score_exceptions = {'Almaty': 2.0, 'Brorfelde': 0.9, 'Estacada': 0.4, 'Jayuya': 0.6, 'Karlukovo': 2.2,  'Morgantown': 2.9,\n",
+    " 'Nordkapp': 1.5, 'Nullarbor': 2.2,  'Puente-Laguna-Garzonkuala-Penyu': 0.4, 'Uzupis': 0.9}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 44,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "| Destination | Score |\n",
+      "|-------------|-------|\n",
+      "| Almaty | 2.0 |\n",
+      "| Brorfelde | 0.9 |\n",
+      "| Estacada | 0.4 |\n",
+      "| Jayuya | 0.6 |\n",
+      "| Karlukovo | 2.2 |\n",
+      "| Morgantown | 2.9 |\n",
+      "| Nordkapp | 1.5 |\n",
+      "| Nullarbor | 2.2 |\n",
+      "| Puente-Laguna-Garzonkuala-Penyu | 0.4 |\n",
+      "| Uzupis | 0.9 |\n"
+     ]
+    }
+   ],
+   "source": [
+    "print('| Destination | Score |')\n",
+    "print('|-------------|-------|')\n",
+    "for n in sorted(destination_scores):\n",
+    "    if destination_scores[n] != 1:\n",
+    "        print('|', n, '|', destination_scores[n], '|')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 48,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def make_holiday(name=None):\n",
+    "    if not name:\n",
+    "        name = random.choice(destination_names)\n",
+    "    days = random.choice([3, 7, 7, 7, 10, 14, 14, 14, 14, 21, 21])\n",
+    "    price = 0\n",
+    "    for _ in range(4):\n",
+    "        price += random.randint(100, 500)\n",
+    "    hol_id = str(uuid.uuid4())\n",
+    "    return hol_id, price, name, days"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 54,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "('4615dad7-f5ab-4c9b-8028-b3e5c676ff24', 1046, 'Almaty', 14)"
+      ]
+     },
+     "execution_count": 54,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "make_holiday()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 59,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[('3c425201-5538-4a3f-bfd7-1219137c9d63', 1147, 'Aalborg', 21),\n",
+       " ('5913e357-dc18-49c5-850d-aa0172041cc4', 1398, 'Nullarbor', 3),\n",
+       " ('bc966859-49ad-4c26-b36e-94251b0a29b5', 1064, 'Morgantown', 7),\n",
+       " ('ab1d0a54-41bc-4351-beb8-f6e5fd4f07f0', 1722, 'Estacada', 14),\n",
+       " ('b5efba4e-373d-4a15-b048-8fcb3169c441', 1132, 'Almaty', 7),\n",
+       " ('bd1ff2b9-5b97-4a13-9d8a-601faea40e9c', 1085, 'Tambon-Pa-Fa', 14),\n",
+       " ('5b9df004-a8b7-4c28-a27e-21e24cd566b5', 1264, 'Lemnos', 7),\n",
+       " ('5951de60-9e98-471f-a917-74e3c8a3457a', 938, 'Sofia', 14),\n",
+       " ('c6a4cad7-cd9a-4e05-bd16-92305c933269',\n",
+       "  922,\n",
+       "  'Puente-Laguna-Garzonkuala-Penyu',\n",
+       "  14),\n",
+       " ('9527ee0b-4bcd-4a1f-95fd-b3a627eacf02', 1071, 'Hajnowski', 14),\n",
+       " ('82b6adfb-f09d-420f-bbf9-ea90450d21f6', 734, 'Karlukovo', 3),\n",
+       " ('7b08192c-5e30-45dc-bb31-2da61861c0ac', 1692, 'Mamula', 21),\n",
+       " ('5abbe3e4-7d2e-404c-9ce2-27083f95c140', 1277, 'Stonington-Island', 7),\n",
+       " ('b3f517ca-2a07-427d-8531-81227468b611', 1280, 'Grimsey-Island', 3),\n",
+       " ('f1fa90d2-0f58-480f-80c0-0fddb845b71a', 1225, 'Uzupis', 7),\n",
+       " ('330e4f58-31d2-474f-8e23-654224689a18', 1016, 'Sukhumi', 14),\n",
+       " ('a6837ba1-42aa-488d-b39a-5b49422ce165', 966, 'Ijsseloog', 21),\n",
+       " ('a7e4161a-0435-4915-961e-8c204e527a4b', 1465, 'Giessenmestia', 21),\n",
+       " ('633be2e4-a719-496e-9987-d5ea8b6ab428', 1256, 'Nordkapp', 3),\n",
+       " ('bd83d3e3-6134-4511-918c-a94338ffb0c8', 1508, 'Gorongosa', 7),\n",
+       " ('05ed4593-3582-4fde-8958-a63274507344', 1099, 'Brorfelde', 7),\n",
+       " ('b8361d0a-7f23-4491-9450-c28917807a68', 1364, 'Parowan', 7),\n",
+       " ('dc7f49c2-672e-4abc-a58a-4e8b45e786d7', 1491, 'Tubakuba', 14),\n",
+       " ('b709a89e-e5c5-4a60-97ca-55ad350fa7f1', 1373, 'Geoje-Si', 7),\n",
+       " ('18888ae2-e410-4430-87af-1d07ba9b25bb', 1317, 'Mora', 3),\n",
+       " ('b08ebc25-7d02-4973-8e28-fa3b75ed4e29', 1483, 'Holmegaard', 14),\n",
+       " ('d3519dde-9a15-4982-b1ed-1dd6dbecc2c1', 653, 'Jayuya', 21),\n",
+       " ('fa882848-1787-424a-90c3-8593bb91f174', 1027, 'Zhangye-Shi', 10),\n",
+       " ('21d2fcc8-f528-467d-b0ba-a6748933a4a8', 1261, 'Luoyang', 14)]"
+      ]
+     },
+     "execution_count": 59,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "holidays = []\n",
+    "for n in destination_names:\n",
+    "    holidays += [make_holiday(n)]\n",
+    "holidays"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 60,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "for _ in range(95):\n",
+    "    holidays += [make_holiday()]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 62,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "random.shuffle(holidays)\n",
+    "with open('01-holidays.txt', 'w') as f:\n",
+    "    for hid, price, name, days in holidays:\n",
+    "        f.write('{} {} {} {}\\n'.format(hid[-10:], price, name, days))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 63,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[['5f12ce1b86', '1192', 'Sukhumi', '14'],\n",
+       " ['0279c8a91b', '1008', 'Estacada', '14'],\n",
+       " ['1faea40e9c', '1085', 'Tambon-Pa-Fa', '14']]"
+      ]
+     },
+     "execution_count": 63,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "with open('01-holidays.txt') as f:\n",
+    "    hols = [h.split() for h in f.readlines()]\n",
+    "hols[:3]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 64,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "assert len(set(h[0] for h in hols)) == len(hols)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 78,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[('6138068a-3c16-4f7f-8dc6-a1199608abc5', 1209, 'Nordkapp', 21),\n",
+       " ('eafb15a4-1839-4fb5-be9b-d8389018bd07', 1052, 'Estacada', 21),\n",
+       " ('ab659b71-347d-45dc-9416-34def36ffc7d', 1514, 'Giessenmestia', 21),\n",
+       " ('bb8d5034-49ce-483d-ab6c-d16caf2584a5', 724, 'Stonington-Island', 14),\n",
+       " ('7476b214-8b55-47f6-833e-dfa487c4270a', 782, 'Geoje-Si', 14),\n",
+       " ('f2ffe169-7cc5-42e1-9b46-8cdb61bb906d', 769, 'Morgantown', 3),\n",
+       " ('2e6a6d6d-6c08-4021-b99f-05202c898b5f', 1184, 'Morgantown', 21)]"
+      ]
+     },
+     "execution_count": 78,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "example_holidays = []\n",
+    "names = random.sample(destination_score_exceptions.keys(), 2) + random.sample(destination_names, 4)\n",
+    "names += [names[-1]]\n",
+    "example_holidays = [make_holiday(n) for n in names]\n",
+    "example_holidays"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 79,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[('f2ffe169-7cc5-42e1-9b46-8cdb61bb906d', 769, 'Morgantown', 3),\n",
+       " ('2e6a6d6d-6c08-4021-b99f-05202c898b5f', 1184, 'Morgantown', 21),\n",
+       " ('ab659b71-347d-45dc-9416-34def36ffc7d', 1514, 'Giessenmestia', 21),\n",
+       " ('eafb15a4-1839-4fb5-be9b-d8389018bd07', 1052, 'Estacada', 21),\n",
+       " ('7476b214-8b55-47f6-833e-dfa487c4270a', 782, 'Geoje-Si', 14),\n",
+       " ('bb8d5034-49ce-483d-ab6c-d16caf2584a5', 724, 'Stonington-Island', 14),\n",
+       " ('6138068a-3c16-4f7f-8dc6-a1199608abc5', 1209, 'Nordkapp', 21)]"
+      ]
+     },
+     "execution_count": 79,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "random.shuffle(example_holidays)\n",
+    "example_holidays"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 82,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "example_holidays = [('f2ffe169-7cc5-42e1-9b46-8cdb61bb906d', 769, 'Morgantown', 3),\n",
+    " ('2e6a6d6d-6c08-4021-b99f-05202c898b5f', 1284, 'Morgantown', 21),\n",
+    " ('ab659b71-347d-45dc-9416-34def36ffc7d', 1514, 'Giessenmestia', 21),\n",
+    " ('eafb15a4-1839-4fb5-be9b-d8389018bd07', 1052, 'Estacada', 21),\n",
+    " ('7476b214-8b55-47f6-833e-dfa487c4270a', 782, 'Geoje-Si', 14),\n",
+    " ('bb8d5034-49ce-483d-ab6c-d16caf2584a5', 724, 'Stonington-Island', 14),\n",
+    " ('6138068a-3c16-4f7f-8dc6-a1199608abc5', 1209, 'Nordkapp', 21)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 83,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "db61bb906d 769 Morgantown 3\n",
+      "202c898b5f 1284 Morgantown 21\n",
+      "def36ffc7d 1514 Giessenmestia 21\n",
+      "389018bd07 1052 Estacada 21\n",
+      "a487c4270a 782 Geoje-Si 14\n",
+      "6caf2584a5 724 Stonington-Island 14\n",
+      "199608abc5 1209 Nordkapp 21\n"
+     ]
+    }
+   ],
+   "source": [
+    "for hid, price, name, days in example_holidays:\n",
+    "        print('{} {} {} {}'.format(hid[-10:], price, name, days))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "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.5.2+"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/01-ticket-prices/ticket-pricing-solution.ipynb b/01-ticket-prices/ticket-pricing-solution.ipynb
new file mode 100644 (file)
index 0000000..59d7046
--- /dev/null
@@ -0,0 +1,285 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Ticket pricing\n",
+    "\n",
+    "You've been shopping around for a holiday package deal and its time to make your choice of which deal to go with. The file [01-holidays.txt](01-holidays.txt) contains a summary of your investigations. \n",
+    "\n",
+    "It's a simple text file, with one possible holiday package per line.\n",
+    "\n",
+    "Each line has four fields, separated by spaces. They are:\n",
+    "* The deal ID, from the price comparison website you found it.\n",
+    "* The holiday price, in whole pounds.\n",
+    "* The location of the holiday, always a single word.\n",
+    "* The number of nights you'd be staying. \n",
+    "\n",
+    "For example, the data file might look like this:\n",
+    "\n",
+    "```\n",
+    "db61bb906d 769 Morgantown 3\n",
+    "202c898b5f 1284 Morgantown 21\n",
+    "def36ffc7d 1514 Giessenmestia 21\n",
+    "389018bd07 1052 Estacada 21\n",
+    "a487c4270a 782 Geoje-Si 14\n",
+    "6caf2584a5 724 Stonington-Island 14\n",
+    "199608abc5 1209 Nordkapp 21\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Part 1\n",
+    "You have a budget of £1200. How many of the holidays can you afford?\n",
+    "\n",
+    "Given the example data above, you could afford four of the holidays: the 21 day trip to Morgantown and the trips to  Giessenmestia and Nordkapp are all too expensive."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Solution"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[['5f12ce1b86', '1192', 'Sukhumi', '14'],\n",
+       " ['0279c8a91b', '1008', 'Estacada', '14'],\n",
+       " ['1faea40e9c', '1085', 'Tambon-Pa-Fa', '14']]"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "holidays = []\n",
+    "with open('01-holidays.txt') as f:\n",
+    "    for hol_line in f.readlines():\n",
+    "        holidays.append(hol_line.split())\n",
+    "        \n",
+    "holidays[:3]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "57"
+      ]
+     },
+     "execution_count": 25,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "affordable_holidays = []\n",
+    "for h in holidays:\n",
+    "    if int(h[1]) <= 1200:\n",
+    "        affordable_holidays.append(h)\n",
+    "\n",
+    "len(affordable_holidays)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Smart-alec one-line solution"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "57"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "sum(1 for h in open('01-holidays.txt').readlines() if int(h.split()[1]) <= 1200)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Part 2\n",
+    "You don't just want _a_ holiday. You want the _best_ holiday. What is the code of the holiday which would give you the best value?\n",
+    "\n",
+    "The \"value\" of a holiday is the duration per pound. Because some destinations are better than others, you'll want to scale the value for some locations. For instance, a night in Timbuktu is worth three times as much as a holiday in Bletchley.\n",
+    "\n",
+    "Assume all holidays have a relative value of 1, apart from these destinations.\n",
+    "\n",
+    "| Destination | Score |\n",
+    "|-------------|-------|\n",
+    "| Almaty | 2.0 |\n",
+    "| Brorfelde | 0.9 |\n",
+    "| Estacada | 0.4 |\n",
+    "| Jayuya | 0.6 |\n",
+    "| Karlukovo | 2.2 |\n",
+    "| Morgantown | 2.9 |\n",
+    "| Nordkapp | 1.5 |\n",
+    "| Nullarbor | 2.2 |\n",
+    "| Puente-Laguna-Garzonkuala-Penyu | 0.4 |\n",
+    "| Uzupis | 0.9 |\n",
+    "\n",
+    "## Example\n",
+    "\n",
+    "Given the holiday list above, the holiday to Geoje-Si (with the standard weighting of 1) has a value of $\\frac{14}{782} = 0.0179$ nights per pound. The best value holiday is the 21 day trip to Morgantown, with a value of $2.9 \\times \\frac{21}{1284} = 0.0474$ nights per pound. Unfortunately, it's unaffordable. \n",
+    "\n",
+    "The trip to Estacada looks promising, at $\\frac{21}{1052} = 0.0200$ nights per pound. Unfortunately, the weighting for Estacada is low, to the adjusted cost is $0.4 \\times \\frac{21}{1052} = 0.00798$ nights per pound.\n",
+    "\n",
+    "The best value affordable holiday is the trip to Stonnington Island, with $\\frac{14}{1284} = 0.0193$ nights per pound."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "destination_values = {'Almaty': 2.0, 'Brorfelde': 0.9, 'Estacada': 0.4, 'Jayuya': 0.6, 'Karlukovo': 2.2, \n",
+    "                      'Morgantown': 2.9,'Nordkapp': 1.5, 'Nullarbor': 2.2, \n",
+    "                      'Puente-Laguna-Garzonkuala-Penyu': 0.4, 'Uzupis': 0.9}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def value_of_destination(name):\n",
+    "    if name in destination_values:\n",
+    "        return destination_values[name]\n",
+    "    else:\n",
+    "        return 1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def value_of_holiday(holiday):\n",
+    "    hid, cost, destination, duration = tuple(holiday)\n",
+    "    value = value_of_destination(destination) * float(duration) / int(cost)\n",
+    "    return value"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 36,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'dc16c9b87f'"
+      ]
+     },
+     "execution_count": 36,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "best_holiday = ''\n",
+    "best_value = 0\n",
+    "\n",
+    "for h in affordable_holidays:\n",
+    "    if value_of_holiday(h) > best_value:\n",
+    "        best_value = value_of_holiday(h)\n",
+    "        best_holiday = h[0]\n",
+    "        \n",
+    "best_holiday"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Smart-alec solution"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'dc16c9b87f'"
+      ]
+     },
+     "execution_count": 34,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "max(affordable_holidays, key=value_of_holiday)[0]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "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.5.2+"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}