みなさん閏年が何か知ってるよね???
・・・ええ勿論ご存知だろう。詳しくはウィキペディアをご覧あれ。今採用されているのはグレゴリオ暦の法則。
法則は下記の通り。案外間違えやすいのではなかろうか。
- 西暦年が4で割り切れる年は閏年
- ただし、西暦年が100で割り切れる年は平年
- ただし、西暦年が400で割り切れる年は閏年
じゃあ閏年の列挙はどうやればいいのか???
よくやる考え方は、if文とかで各年が4で割り切れるか?100で割り切れるか??とかをやると思われる。そのようなやり方は他のWebでたくさん記載されていると思うので、もっと違う発想でやる方法を書いてみる。
UECのサイトに下記の記事が書いてあるのを思い出した。まずはデータを準備しておいて、データ同士の重複比較やマージを使うことで、if文などの制御構造無しでスッキリと処理が書けるということ。
UEC - usp engineers' community - UECジャーナル
つまり下記のデータを準備し、それらをcat
、sort
、uniq
などのコマンドで重複比較やマージすることで閏年を出してみることにする。
- 4で割り切れる年のデータ
- 100で割り切れる年のデータ
- 400で割り切れる年のデータ
これらのデータを準備して、1.のデータから2.のデータを排除し、さらに3.のデータをマージしてやればいいのだ。
では20世紀から24世紀までの閏年を列挙してみよう。まずは上記の3つのデータを作る。
$ seq 1901 2400 | awk '$1%4==0' > year4
$ seq 1901 2400 | awk '$1%100==0' > year100
$ seq 1901 2400 | awk '$1%400==0' > year400
$ head year*
==> year100 <==
2000
2100
2200
2300
2400
==> year4 <==
1904
1908
1912
1916
1920
1924
1928
1932
1936
==> year400 <==
2000
2400
では準備した3つのデータを元に、グレゴリオ暦の閏年法則に則って処理してみる。
# 1. 西暦年が4で割り切れる年は閏年
$ cat year4
1904
1908
1912
1916
1920
1924
1928
1932
1936
....
2364
2368
2372
2376
2380
2384
2388
2392
2396
2400
# 2. ただし、西暦年が100で割り切れる年は平年
$ cat year4 | cat - year100 | sort | uniq -u
1904
1908
1912
1916
1920
1924
1928
1932
1936
1940
....
2360
2364
2368
2372
2376
2380
2384
2388
2392
2396
# 3. ただし、西暦年が400で割り切れる年は閏年
$ cat year4 | cat - year100 | sort | uniq -u | cat - year400 | sort | uniq
1904
1908
1912
1916
1920
1924
1928
1932
1936
1940
....
2364
2368
2372
2376
2380
2384
2388
2392
2396
2400
ということで、データ重視なアプローチで閏年を列挙した。
ちなみに上記の処理をシェル芸なワンライナーだとこんな感じになる。上記のようなデータ重視なアプローチがあってこそのワンライナー。
$ seq 1900 2400 | awk '$1%4==0' |
> ( cat; seq 1900 2400 | awk '$1%100==0' ) | sort | uniq -u |
> ( cat; seq 1900 2400 | awk '$1%400==0' ) | sort | uniq