連休前の出来事
業務で、1 〜 1500 の数字の中から重複しているものを見つける必要があり、その時に 1 分くらいで書いたのが以下の Perl スクリプトです。
#!/usr/bin/env perl use strict; use warnings; my %hash; for my $line (<DATA>) { chomp $line; $hash{$line}++; } for my $num ( sort keys %hash ) { if ( $hash{$num} > 1 ) { print $num , "\n"; # 3 6 } } __DATA__ 1 2 3 3 4 5 6 6 7 8 9 # 以下、1500まで
重複している 3 と 6 だけ表示されます。
こんな感じでちゃんと動いて用はたせたんですが、問題は 1 行書くたびに
「絶対に重複してるものを選び出す関数あるだろ」
「たしか、List::Util
ってモジュールに uniq
っていう重複のない値を出す関数があったから、その逆もあるに違いない」
「ここでググってみるか、いや、このまま書き続けた方がいいか」
「いや grep
とか使ってなんとかできるんじゃないのか」
「というか、元のデータ Google Sheet だからそっちでも重複検出する何かあるだろ何か」
という思いが繰り返し去来することでした。
まぁ、時間あれば調べたんですが、こんときはトラブルシュートでとりあえず速度が必要でした。
重複した値を見つける
これ、ブログのネタになるなーと思って連休に突入したのですが、なんか夜更かししたり映画観に行ったりしているうちに最終日になってしまいました。
ここで書かないと忘れるよなぁ、ってことで書きます。
List::MoreUtils の duplicates
Perl の外部モジュールです。cpanm でサクッとインストールしましょう。
$ cpanm List::MoreUtils
使う関数は duplicates 、そのまま重複って意味です
#!/usr/bin/env perl use strict; use warnings; use List::MoreUtils qw/duplicates/; my @duplicates_nums = duplicates(<DATA>); chomp @duplicates_nums; print "@duplicates_nums"; # 3 6 __DATA__ 1 2 3 3 4 5 6 6 7 8 9
・・・こっちで良かったじゃん。duplicates ってちゃんとやりたい名前もついてて、あとから見た人(数日後の自分)にも優しい。
まぁ次回からはこっち使おう・・・
grep つかう
あんまり短くならなかった。
#!/usr/bin/env perl use strict; use warnings; my %hash; grep {chomp $_;$hash{$_}++} (<DATA>); for my $num ( sort keys %hash ) { if ( $hash{$num} > 1 ) { print $num , "\n"; } } __DATA__ 1 2 3 3 4 5 6 6 7 8 9
grep の中に全部入れてもいいけど可読性良くない
#!/usr/bin/env perl use strict; use warnings; my %hash; grep { chomp $_; $hash{$_}++; print "$_\n" if $hash{$_} > 1 } (<DATA>); __DATA__ 1 2 3 3 4 5 6 6 7 8 9
Google Sheet の関数
列、または行から直接重複している値のみを抜き出す関数はなさそう。
シート上部のメニューにある「データ」のなかに「重複の削除」というのはあるけど、重複している値のみを表示するってのはなかった。
だもんで、COUNTIF で重複する値を探してソートって感じ?
query 関数とか使えばいいかな?(やってない(SQL でいうところの HAVING
句がないから難しそう
ってことで
重複した値探す時には List::MoreUtils
使うと楽で良いよね、という話でした。