ミリ秒単位で最新のタイムスタンプと一致

ミリ秒単位で最新のタイムスタンプと一致

以下のような大きなdata.txtファイルがあります。各タイムスタンプについて、5分後に最も近い時刻一致と列4の値を見つける必要があります。これで、2つの新しい列に両方を印刷します。

たとえば、「2018-02-16 16:45:29.557 Farad 0.0004300000」の場合は、5分後(たとえば約)16:50:40.486 Farad 0.0002400000以降に利用可能な最良の時間を見つける必要があります。

これには正確な時刻一致がないため、最新の一致のみが必要です。また、日付が2018-02-16から2018-02-17に変更された場合は、コードを円滑に実行する必要があります。

最終出力は次のようにする必要があります

"2018-02-16      16:45:29.557    farads  0.0004300000 16:50:40.486 0.0002400000"

どうすればいいですか?

   col1       col2       col3      col4
2018-02-16 16:46:09.300 farads 0.0004300000
2018-02-16 16:47:10.987 farads 0.0002800000
2018-02-16 16:47:51.611 farads 0.0006500000
2018-02-16 16:47:51.612 farads 0.0006500000
2018-02-16 16:48:34.077 farads 0.0006600000
2018-02-16 16:49:17.015 farads 0.0003300000
2018-02-16 16:49:59.075 farads 0.0000700000
2018-02-16 16:50:40.486 farads 0.0002400000
2018-02-16 16:51:22.525 farads 0.0005900000
2018-02-16 16:52:01.997 farads 0.0003900000
2018-02-16 16:52:43.612 farads 0.0005200000
2018-02-16 16:53:23.550 farads 0.0003900000
2018-02-16 16:54:03.276 farads 0.0005300000
2018-02-16 16:54:44.223 farads 0.0003800000
2018-02-16 16:55:24.769 farads 0.0003200000
2018-02-16 16:56:10.028 farads 0.0002700000
2018-02-16 16:56:57.624 farads 0.0000900000
2018-02-16 16:57:37.387 farads 0.0003000000
2018-02-16 16:58:16.929 farads 0.0005800000
2018-02-16 16:58:56.961 farads 0.0003000000
2018-02-16 16:59:39.217 farads 0.0001900000
2018-02-16 17:00:19.129 farads 0.0005800000
2018-02-16 17:00:59.328 farads 0.0001500000
2018-02-16 17:01:39.138 farads 0.0005400000
2018-02-16 17:02:19.786 farads 0.0006600000
2018-02-16 17:03:00.236 farads 0.0004700000
2018-02-16 17:03:44.343 farads 0.0003300000
2018-02-16 17:04:24.996 farads 0.0002200000
2018-02-16 17:05:05.754 farads 0.0003200000
2018-02-16 17:05:48.512 farads 0.0004600000
2018-02-16 17:06:29.248 farads 0.0003700000
2018-02-16 17:07:09.819 farads 0.0001300000
2018-02-16 17:07:50.392 farads 0.0005500000
2018-02-16 17:08:32.397 farads 0.0002000000
2018-02-16 17:09:14.778 farads 0.0003000000
2018-02-16 17:09:57.688 farads 0.0003100000
2018-02-16 17:10:37.237 farads 0.0003900000
2018-02-16 17:11:21.559 farads 0.0003500000
2018-02-16 17:12:00.945 farads 0.0003500000
2018-02-16 17:12:00.946 farads 0.0003500000
2018-02-16 17:12:44.127 farads 0.0003200000
2018-02-16 17:13:26.579 farads 0.0003800000
2018-02-16 17:14:09.175 farads 0.0001100000
2018-02-16 17:14:49.552 farads 0.0001300000
2018-02-16 17:14:49.553 farads 0.0001300000
2018-02-16 17:15:31.044 farads 0.0002000000
2018-02-16 17:16:12.038 farads 0.0000400000
2018-02-16 17:16:12.039 farads 0.0000400000
2018-02-16 17:16:52.956 farads 0.0002300000
2018-02-16 17:17:33.238 farads 0.0001900000
2018-02-16 17:18:12.986 farads 0.0001900000
2018-02-16 17:18:12.987 farads 0.0001900000
2018-02-16 17:18:54.214 farads 0.0002300000
2018-02-16 17:19:34.432 farads 0.0001500000
2018-02-16 17:20:22.002 farads 0.0000700000
2018-02-16 17:21:03.320 farads 0.0001100000
2018-02-16 17:21:43.477 farads 0.0002000000
2018-02-16 17:22:27.400 farads 0.0003500000
2018-02-16 17:23:11.224 farads 0.0001700000
2018-02-16 17:23:52.907 farads 0.0001100000
2018-02-16 17:24:40.392 farads 0.0001500000
2018-02-16 17:25:23.026 farads 0.0001400000
2018-02-16 17:26:03.886 farads 0.0003100000
2018-02-16 17:26:45.191 farads 0.0001900000
2018-02-16 17:26:45.192 farads 0.0001900000
2018-02-16 17:27:28.652 farads 0.0001000000
2018-02-16 17:28:09.625 farads 0.0002000000
2018-02-16 17:28:49.753 farads 0.0001500000
2018-02-16 17:29:29.224 farads 0.0005600000
2018-02-16 17:30:10.520 farads 0.0002100000
2018-02-16 17:30:50.702 farads 0.0001700000
2018-02-16 17:31:30.077 farads 0.0004800000
2018-02-16 17:32:11.586 farads 0.0003800000
2018-02-16 17:32:51.434 farads 0.0003600000
2018-02-16 17:33:31.457 farads 0.0005300000
2018-02-16 17:34:10.910 farads 0.0007600000
2018-02-16 17:34:51.174 farads 0.0004400000
2018-02-16 17:34:51.175 farads 0.0004400000
2018-02-16 17:35:31.234 farads 0.0004800000
2018-02-16 17:36:22.164 farads 0.0002600000
2018-02-16 17:37:02.616 farads 0.0004100000
2018-02-16 17:37:42.127 farads 0.0003500000
2018-02-16 17:38:23.346 farads 0.0004100000
2018-02-16 17:39:04.611 farads 0.0002400000
2018-02-16 17:39:46.119 farads 0.0000700000
2018-02-16 17:40:33.633 farads 0.0001500000
2018-02-16 17:41:13.307 farads 0.0001500000
2018-02-16 17:41:13.308 farads 0.0001500000
2018-02-16 17:41:54.643 farads 0.0003100000
2018-02-16 17:42:33.994 farads 0.0002300000
2018-02-16 17:43:14.389 farads 0.0004000000
2018-02-16 17:43:54.324 farads 0.0002200000
2018-02-16 17:44:36.122 farads 0.0001800000
2018-02-16 17:45:16.828 farads 0.0002600000
2018-02-16 17:45:59.158 farads 0.0001500000
2018-02-16 17:46:45.126 farads 0.0000700000
2018-02-16 17:47:25.236 farads 0.0004400000
2018-02-16 17:48:12.096 farads 0.0002200000
2018-02-16 17:49:01.891 farads 0.0001600000
2018-02-16 17:49:50.422 farads 0.0002100000
2018-02-16 17:50:31.222 farads 0.0001300000
2018-02-16 17:51:12.651 farads 0.0002600000
2018-02-16 17:51:12.652 farads 0.0002600000
2018-02-16 17:51:53.478 farads 0.0001300000
2018-02-16 17:52:34.145 farads 0.0004600000
2018-02-16 17:53:14.374 farads 0.0003300000
2018-02-16 23:53:53.906 farads 0.0002600000
2018-02-16 23:54:34.453 farads 0.0001200000
2018-02-16 23:55:15.512 farads 0.0001600000
2018-02-16 23:55:58.161 farads 0.0001800000
2018-02-16 23:56:46.602 farads 0.0002600000
2018-02-16 23:57:26.829 farads 0.0003100000
2018-02-16 23:57:26.830 farads 0.0003100000
2018-02-16 23:58:06.991 farads 0.0004400000
2018-02-16 23:58:47.104 farads 0.0003600000
2018-02-16 23:58:47.105 farads 0.0003600000
2018-02-16 23:59:27.080 farads 0.0002300000
2018-02-17 00:00:07.008 farads 0.0002900000
2018-02-17 00:00:07.009 farads 0.0002900000
2018-02-17 00:00:51.685 farads 0.0004900000
2018-02-17 00:01:30.835 farads 0.0003000000
2018-02-17 00:02:14.187 farads 0.0004300000
2018-02-17 00:02:56.048 farads 0.0004700000
2018-02-17 00:03:39.758 farads 0.0004200000
2018-02-17 00:04:19.990 farads 0.0001600000
2018-02-17 00:04:59.854 farads 0.0001700000
2018-02-17 00:05:40.967 farads 0.0001400000
2018-02-17 00:06:24.584 farads 0.0001000000
2018-02-17 00:07:04.742 farads 0.0002500000
2018-02-17 00:07:48.107 farads 0.0003600000
2018-02-17 00:08:31.136 farads 0.0000700000
2018-02-17 00:09:12.429 farads 0.0001500000
2018-02-17 00:09:59.567 farads 0.0002500000
2018-02-17 00:10:41.062 farads 0.0001900000
2018-02-17 00:11:21.016 farads 0.0001600000
2018-02-17 00:12:00.863 farads 0.0001600000
2018-02-17 00:12:41.023 farads 0.0002400000
2018-02-17 00:13:22.429 farads 0.0001500000
2018-02-17 00:14:04.826 farads 0.0004100000
2018-02-17 00:14:51.079 farads 0.0001600000
2018-02-17 00:15:31.247 farads 0.0003500000
2018-02-17 00:16:17.396 farads 0.0001900000
2018-02-17 00:16:56.912 farads 0.0002100000
2018-02-17 00:17:37.895 farads 0.0001800000
2018-02-17 00:18:18.354 farads 0.0003700000
2018-02-17 00:18:58.071 farads 0.0004700000
2018-02-17 18:19:38.135 farads 0.0002000000
2018-02-17 18:20:22.373 farads 0.0002600000
2018-02-17 18:21:02.161 farads 0.0003000000
2018-02-17 18:21:43.806 farads 0.0002700000
2018-02-17 18:22:25.394 farads 0.0002500000
2018-02-17 18:23:06.549 farads 0.0003100000
2018-02-17 18:23:46.638 farads 0.0002100000
2018-02-17 18:24:27.966 farads 0.0001800000
2018-02-17 18:25:11.832 farads 0.0002800000
2018-02-17 18:25:52.344 farads 0.0003000000
2018-02-17 18:26:33.672 farads 0.0002600000
2018-02-17 18:27:15.499 farads 0.0004300000
2018-02-17 18:27:55.288 farads 0.0004800000
2018-02-17 18:28:56.699 farads 0.0004200000
2018-02-17 18:29:40.909 farads 0.0002100000
2018-02-17 18:30:20.942 farads 0.0003400000
2018-02-17 18:31:03.937 farads 0.0003500000
2018-02-17 18:31:51.329 farads 0.0002500000
2018-02-17 18:32:32.608 farads 0.0005000000
2018-02-17 18:33:12.869 farads 0.0004900000
2018-02-17 18:33:52.725 farads 0.0002300000
2018-02-17 18:34:39.022 farads 0.0001300000
2018-02-17 18:35:20.579 farads 0.0002800000
2018-02-17 18:36:00.487 farads 0.0002400000
2018-02-17 18:36:51.908 farads 0.0004500000
2018-02-17 18:37:33.667 farads 0.0002500000
2018-02-17 18:38:13.989 farads 0.0004700000
2018-02-17 18:38:53.753 farads 0.0003500000
2018-02-17 18:39:34.052 farads 0.0004100000

ベストアンサー1

メモ:最初にこの記事を投稿したとき、その時間より5分前の時間がそれ以降の時間と一致しないようにするバグがコードにありました。当時はバグを修正する時間がなくて文を削除しましたが、今はバグを修正しなければならず、答えを削除解除しました。しかし、予想出力を1行だけ提供したためこのコードをテストしてみてください。より広範なサンプル入力セットを対象としています。

CPUの時間が心配されないと言われましたが、最初に各行を他の行と比較して強制する試みは、1800行のファイルで実行するのに30秒かかったため、ハッシュで最適化しました。%minsコアは時間は分単位で正確なので、各タイムスタンプで+4分、+5分、+6分だけ考慮されます。このバージョンでは、約4000行の入力ファイルを実行するのに約4秒かかります。

use warnings;
use strict;
use DateTime;
use DateTime::Format::Strptime;

my $strp = DateTime::Format::Strptime->new( on_error=>'croak',
    pattern => '%Y-%m-%d %H:%M:%S.%3N' );
my (@recs, %mins);
while (<>) {
    m{\A\s* ([-\d]+) \s+ ([\d:.]+) \s+farads\s+ ((?:\d+\.)?\d+) \s*\z}ixms
        or die "failed to parse line: $_";
    my $dt  = $strp->parse_datetime("$1 $2");
    my $min = int($dt->epoch/60);
    my $rec = { min=>$min, farads=>$3, dt=>$dt, seek=>$dt->clone->add(minutes=>5) };
    push @{ $mins{ $min } }, $rec;
    push @recs, $rec;
}

for my $cur (@recs) {
    my @candidates = (
        @{ $mins{$cur->{min}+4} // [] },
        @{ $mins{$cur->{min}+5} // [] },
        @{ $mins{$cur->{min}+6} // [] }  );
    my ($min_diff_ms,$min_other);
    for my $other (@candidates) {
        my $diff_ms = abs($cur->{seek}->subtract_datetime_absolute($other->{dt})
            ->in_units('nanoseconds'))/1e6;
        if (!defined $min_diff_ms || $diff_ms<$min_diff_ms) {
            $min_diff_ms = $diff_ms;
            $min_other = $other;
        }
    }
    print $cur->{dt}->strftime('%Y-%m-%d %H:%M:%S.%3N')," farads ",
        $cur->{farads}, defined($min_other) ? ( " ",
            $min_other->{dt}->strftime('%Y-%m-%d %H:%M:%S.%3N')," ",
            $min_other->{farads} ) : '', "\n";
}

オリジナルサンプル入力:

 2018-02-16      16:45:29.557    farads  0.0004300000
 2018-02-16      16:45:29.557    farads  0.0004300000
 2018-02-16      16:45:29.558    farads  0.0004300000
 2018-02-16      16:46:09.300    farads  0.0004300000
 2018-02-16      16:47:10.987    farads  0.0002800000
 2018-02-16      16:47:51.611    farads  0.0006500000
 2018-02-16      16:47:51.612    farads  0.0006500000
 2018-02-16      16:48:34.077    farads  0.0006600000
 2018-02-16      16:49:17.015    farads  0.0003300000
 2018-02-16      16:49:59.075    farads  0.0000700000
 2018-02-16      16:50:40.486    farads  0.0002400000
 2018-02-16      16:51:22.525    farads  0.0005900000
 2018-02-16      16:52:01.997    farads  0.0003900000

この入力の出力は次のとおりです。

2018-02-16 16:45:29.557 farads 0.0004300000 2018-02-16 16:50:40.486 0.0002400000
2018-02-16 16:45:29.557 farads 0.0004300000 2018-02-16 16:50:40.486 0.0002400000
2018-02-16 16:45:29.558 farads 0.0004300000 2018-02-16 16:50:40.486 0.0002400000
2018-02-16 16:46:09.300 farads 0.0004300000 2018-02-16 16:51:22.525 0.0005900000
2018-02-16 16:47:10.987 farads 0.0002800000 2018-02-16 16:52:01.997 0.0003900000
2018-02-16 16:47:51.611 farads 0.0006500000 2018-02-16 16:52:01.997 0.0003900000
2018-02-16 16:47:51.612 farads 0.0006500000 2018-02-16 16:52:01.997 0.0003900000
2018-02-16 16:48:34.077 farads 0.0006600000 2018-02-16 16:52:01.997 0.0003900000
2018-02-16 16:49:17.015 farads 0.0003300000
2018-02-16 16:49:59.075 farads 0.0000700000
2018-02-16 16:50:40.486 farads 0.0002400000
2018-02-16 16:51:22.525 farads 0.0005900000
2018-02-16 16:52:01.997 farads 0.0003900000

以下は、ミリ秒を無視してコアモジュールを使用するより高速ですが、より正確ではないバージョンです。Time::Piece 少し重いよりもDateTime (しかし私はまだ後者を強くお勧めします)。上記と比較すると、実行に1秒もかかりません。精度の違いを見ることができますが、±1分も許容されると言われました。

use warnings;
use strict;
use Time::Piece;

my (@recs, %mins);
while (<>) {
    m{\A\s* ([-\d]+) \s+ ([\d:]+)(\.\d+) \s+farads\s+ ((?:\d+\.)?\d+) \s*\z}ixms
        or die "failed to parse line: $_";
    my $dt  = Time::Piece->strptime("$1 $2", '%Y-%m-%d %H:%M:%S');
    my $min = int($dt->epoch/60);
    my $rec = { min=>$min, farads=>$4, timestr=>"$1 $2$3", epoch=>$dt->epoch };
    push @{ $mins{ $min } }, $rec;
    push @recs, $rec;
}

for my $cur (@recs) {
    my @candidates = (
        @{ $mins{$cur->{min}+4} // [] },
        @{ $mins{$cur->{min}+5} // [] },
        @{ $mins{$cur->{min}+6} // [] }  );
    my ($min_diff_s,$min_other);
    for my $other (@candidates) {
        my $diff_s = abs( $other->{epoch} - $cur->{epoch} );
        if (!defined $min_diff_s || $diff_s<$min_diff_s) {
            $min_diff_s = $diff_s;
            $min_other = $other;
        }
    }
    print $cur->{timestr}," farads ",$cur->{farads},
        defined($min_other)
            ? ( " ", $min_other->{timestr}," ",$min_other->{farads} )
            : '', "\n";
}

出力:

2018-02-16 16:45:29.557 farads 0.0004300000 2018-02-16 16:49:17.015 0.0003300000
2018-02-16 16:45:29.557 farads 0.0004300000 2018-02-16 16:49:17.015 0.0003300000
2018-02-16 16:45:29.558 farads 0.0004300000 2018-02-16 16:49:17.015 0.0003300000
2018-02-16 16:46:09.300 farads 0.0004300000 2018-02-16 16:50:40.486 0.0002400000
2018-02-16 16:47:10.987 farads 0.0002800000 2018-02-16 16:51:22.525 0.0005900000
2018-02-16 16:47:51.611 farads 0.0006500000 2018-02-16 16:51:22.525 0.0005900000
2018-02-16 16:47:51.612 farads 0.0006500000 2018-02-16 16:51:22.525 0.0005900000
2018-02-16 16:48:34.077 farads 0.0006600000 2018-02-16 16:52:01.997 0.0003900000
2018-02-16 16:49:17.015 farads 0.0003300000
2018-02-16 16:49:59.075 farads 0.0000700000
2018-02-16 16:50:40.486 farads 0.0002400000
2018-02-16 16:51:22.525 farads 0.0005900000
2018-02-16 16:52:01.997 farads 0.0003900000

(私は通常コードなしで問題に対する完全な解決策を提供しませんが、これは私にとって興味深い問題でした。)

おすすめ記事