πŸ“¦ Monty / ConvertEpisodeSequences

Explore differences in language design, syntax, and developer experience.

β˜… 0 stars β‘‚ 0 forks πŸ‘ 0 watching βš–οΈ MIT License
πŸ“₯ Clone https://github.com/Monty/ConvertEpisodeSequences.git
HTTPS git clone https://github.com/Monty/ConvertEpisodeSequences.git
SSH git clone git@github.com:Monty/ConvertEpisodeSequences.git
CLI gh repo clone Monty/ConvertEpisodeSequences
Monty Williams Monty Williams Update README.md 3d7e8b3 8 days ago πŸ“ History
πŸ“‚ main View all commits β†’
πŸ“„ .gitattributes
πŸ“„ .gitignore
πŸ“„ LICENSE
πŸ“„ README.md
πŸ“„ worst-case_input
πŸ“„ README.md

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

# 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