データの範囲のオーバーラップを計算することは、特に日付/時刻の値を処理する場合、簡単な作業ではありません。
モジュールをお勧めしTime::Piece::Range
ます。コアTime::Piece
モジュールを拡張して日付の範囲を処理し、overlap
メソッドを備えています。
以下のコードrange_from_file
は、ファイルの名前を指定すると、ファイルの名前を含むすべてのレコードから日付を読み取り、オブジェクトの配列を作成する関数を実装しTime::Piece
ます。配列がソートTime::Piece::Range
され、ソートされたリストの最初と最後の要素からオブジェクトが形成されて返されます。
2つのデータファイルでこのサブルーチンを呼び出すと、2つのTime::Piece::Range
オブジェクトが生成され、メソッドの最後の呼び出しで、overlap
2つのファイルに重複する日付/時刻が含まれるかどうかが判別されます。
サンプルファイルに適用するdata1.txt
と、data2.txt
このコードはそれらが重複していることを確認します。
Time::Piece
現在はコアモジュールですが、そうでTime::Piece::Range
はなく、非コアモジュールもインストールする必要がDate::Range
あるDate::Simple
ことに注意してください。ユーティリティはcpan
依存関係を自動的にインストールしますが、Perlインストールを拡張する権限がない場合はこれが問題になる可能性があります。
use strict;
use warnings;
use Time::Piece::Range;
sub range_from_file {
my $file = shift;
open my $fh, '<', $file or die qq(Unable to open "$file" for reading);
my @dates;
while (<$fh>) {
next unless /(\d+\.\d+\.\d+[ ]\d+:\d+)/;
push @dates, Time::Piece->strptime($1, '%Y.%m.%d %H:%M');
}
return Time::Piece::Range->new((sort {$a <=> $b} @dates)[0,-1]);
}
my $r1 = range_from_file('data1.txt');
my $r2 = range_from_file('data2.txt');
print $r1->overlaps($r2) ? 'overlap' : 'distinct';
アップデート
コアモジュール以外は使用できず、strftime
フォーマットには固定長フィールド(など%B
)しか含まれていないと想定している場合は、この代替手段をお勧めします。
データのデコードに使用する形式でrange_from_file
ある追加の$format
パラメーターを取得するようにを変更しました。strftime
各レコードの最初の日付/時刻フィールドの長さは、現在の日付/時刻を指定された形式でフォーマットし、結果の文字列の長さを見つけることによって確立されます。
各ファイルレコードの先頭から同等の文字数が抽出され、ファイルの最初と最後の日付が配列に格納されます@dates
。
2つの日付はオブジェクトに変換され、匿名配列内のファイルの範囲Time::Piece
として返されます。
新しいサブルーチンoverlap
は、2つの範囲が重複しているかどうかをチェックします。最初の終わりが2番目の始まりの前にある場合、または2番目の終わりが最初の始まりの前にある場合、それらは分離されます。それ以外の場合、それらは重複します。
この場合も、このコードは、ファイル内のサンプルデータが重複data1.txt
していることを確認します。data2.txt
use strict;
use warnings;
use Time::Piece 'localtime';
sub range_from_file {
my ($file, $format) = @_;
open my $fh, '<', $file or die qq(Unable to open "$file" for reading);
my $size = length Time::Piece->new->strftime($format);
my @dates;
while (<$fh>) {
pop @dates if @dates >= 2;
push @dates, substr $_, 0, $size;
}
my @range = map Time::Piece->strptime($_, $format), @dates;
return \@range;
}
sub overlap {
my ($r1, $r2) = @_;
return not $r1->[1] < $r2->[0] or $r2->[1] < $r1->[0];
}
my $r1 = range_from_file('data1.txt', '%Y.%m.%d %H:%M');
my $r2 = range_from_file('data2.txt', '%Y.%m.%d %H:%M');
print overlap($r1, $r2) ? 'overlap' : 'distinct';