1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113# Episode Compressor Comparison
This repository contains programs with identical functionality
written in Python, Rust, Go, and Swift.
It began as a simple Python script that compresses sequential TV
episode listings. I later reimplemented it in Rust and Go to compare
how each language handles common programming tasks such as regular
expressions, string manipulation, state management across iterations,
error handling, command-line argument parsing, file I/O, and formatted
output to stdout and stderr.
My goal was to explore differences in language design, syntax, and
developer experience when implementing the same logic.
The repository also includes:
- A worst-case test file and its expected compressed output
- A few real-world example inputs and results
## Usage
```bash
# From a file
./compress_newEpisodes.py newEpisodes-01.txt
./compress_newEpisodes.py newEpisodes-02.txt > newEpisodes-02-out
# From stdin
./newEpisodes.sh | ./compress_newEpisodes.py > newEpisodes.txt
# Help
./compress_newEpisodes.py --help
```
## Background
Each week I run a `newEpisodes.sh` script that lists new episodes
of TV shows on the streaming services I subscribe to. It’s much
easier to check a consolidated list than to scroll through multiple
websites to see what’s newly available.
These listings often include numerically sequential episodes of the
same series interspersed with non-sequential ones, for example:
```
Cassandre, S03E04, The Grey Wolf
Catch and Release, S01E02, Episode 02
Catch and Release, S01E03, Episode 03
Catch and Release, S01E04, Episode 04
Public Enemy, S03E05, Excommunication
Public Enemy, S03E06, The Beast
The Bench, S01E01, Episode 1
The Bench, S01E02, Episode 2
The Bench, S01E03, Episode 3
The Bench, S01E04, Episode 4
Twenty Twelve, S02E001, Boycott - Part 1
Twenty Twelve, S02E002, Boycott - Part 2
```
Which can be reduced by about 50% to:
```
Cassandre, S03E04, The Grey Wolf
Catch and Release, S01E02-04, Episode 02-04
Public Enemy, S03E05, Excommunication
Public Enemy, S03E06, The Beast
The Bench, S01E01-04, Episode 1-4
Twenty Twelve, S02E001-002, Boycott - Part 1-2
```
Doing this manually each week became tedious. While tools like
`sed` or `awk` could automate parts of it, a small Python script
was more effective end maintainable. After validating its correctness,
I reimplemented the same logic in Rust and Go as a learning exercise.
Rust, Go and compiled Swift are faster, but Python still wins for
convenience — it handles a 233 KB, 5,944-line file in under 45 ms,
and there’s no compilation step to worry about.
```
# Run benchmarks
$ hyperfine --warmup 10 \
'./compress_newEpisodes_rust squishTest.txt >/dev/null' \
'./compress_newEpisodes_go squishTest.txt >/dev/null' \
'./compress_newEpisodes_swift squishTest.txt >/dev/null' \
'./compress_newEpisodes.py squishTest.txt >/dev/null' \
'./compress_newEpisodes.swift squishTest.txt >/dev/null'
Benchmark 1: ./compress_newEpisodes_rust squishTest.txt >/dev/null
Time (mean ± σ): 10.0 ms ± 0.3 ms [User: 8.2 ms, System: 1.6 ms]
Range (min … max): 9.6 ms … 11.0 ms 233 runs
Benchmark 2: ./compress_newEpisodes_go squishTest.txt >/dev/null
Time (mean ± σ): 14.1 ms ± 0.2 ms [User: 12.1 ms, System: 2.1ms]
Range (min … max): 13.6 ms … 14.9 ms 181 runs
Benchmark 3: ./compress_newEpisodes_swift squishTest.txt >/dev/null
Time (mean ± σ): 38.3 ms ± 0.5 ms [User: 36.4 ms, System: 1.5ms]
Range (min … max): 37.4 ms … 40.6 ms 73 runs
Benchmark 4: ./compress_newEpisodes.py squishTest.txt >/dev/null
Time (mean ± σ): 44.0 ms ± 0.4 ms [User: 34.7 ms, System: 6.9ms]
Range (min … max): 42.7 ms … 44.6 ms 63 runs
Benchmark 5: ./compress_newEpisodes.swift squishTest.txt >/dev/null
Time (mean ± σ): 364.4 ms ± 1.0 ms [User: 311.3 ms, System: 34.6 ms]
Range (min … max): 362.3 ms … 365.5 ms 10 runs
Summary
./compress_newEpisodes_rust squishTest.txt >/dev/null ran
1.41 ± 0.05 times faster than ./compress_newEpisodes_go squishTest.txt >/dev/null
3.83 ± 0.13 times faster than ./compress_newEpisodes_swift squishTest.txt >/dev/null
4.40 ± 0.14 times faster than ./compress_newEpisodes.py squishTest.txt >/dev/null
36.43 ± 1.10 times faster than ./compress_newEpisodes.swift squishTest.txt >/dev/null
```