各行の数値と一意の数値を計算して要約するスクリプト

各行の数値と一意の数値を計算して要約するスクリプト
timestamp : IDs returned
20160420084726:-
20160420085418:[111783178, 111557953, 111646835, 111413356, 111412662, 105618372, 111413557]
20160420085418:[111413432, 111633904, 111783198, 111792767, 111557948, 111413225, 111413281]
20160420085418:[111413432, 111633904, 111783198, 111792767, 111557948, 111413225, 111413281]
20160420085522:[111344871, 111394583, 111295547, 111379566, 111352520]
20160420090022:[111344871, 111394583, 111295547, 111379566, 111352520]

タイムスタンプ形式はYYYYMMDDhhmmssです。

·広告は、角かっこで囲まれた広告資産IDのカンマ区切りリストです。または - 広告が返されない場合

1日10分ごとに出力するスクリプトを作成する必要があります。

  1. 返されたIDの数

  2. 返された一意のIDの数

  3. スクリプトは、一意のIDまたは完全なIDを提供する必要があるかどうかを選択するコマンドラインパラメータをサポートする必要があります。

上記のログ抜粋を使用した出力例(合計モード):

20160420084:0
20160420085:26
20160420090:5

固有計算モードでは、以下を提供します。

20160420084:0
20160420085:19
20160420090:5

これが私が今まで持っているものです:

#!/usr/bin/bash
awk -F":" ' { print $1":" $2 } ' file.log | sort -r | uniq -c

結果:

1 20160420090022:[111344871, 111394583, 111295547, 111379566, 111352520] 
1 20160420085522:[111344871, 111394583, 111295547, 111379566, 111352520] 
1 20160420085418:[111783178, 111557953, 111646835, 111413356, 111412662, 105618372, 111413557] 
2 20160420085418:[111413432, 111633904, 111783198, 111792767, 111557948, 111413225, 111413281] 
1 20160420084726:- 
7: –

答え1

配列の配列を処理するにはGNU awkを使用してください(length(array)ただし、現在のほとんどのawkはこれを行います):

$ cat tst.awk
BEGIN { FS=OFS=":" }
NR>1 {
    time = substr($1,1,11)
    totIds[time] += 0
    if ( gsub(/[][ ]/,"",$2) ) {
        totIds[time] += split($2,ids,/,/)
        for ( i in ids ) {
            unqIds[time][ids[i]]
        }
    }
}
END {
    for ( time in totIds ) {
        print time, ( type ~ /^tot/ ? totIds[time] : length(unqIds[time]) )
    }
}

$ awk -v type='tot' -f tst.awk file
20160420084:0
20160420085:26
20160420090:5

$ awk -v type='unq' -f tst.awk file
20160420084:0
20160420085:19
20160420090:5

GNU awkがない場合は、コードとメモリ使用量がわずかに増加するため、同じ操作を実行するためにawkを使用できます。

$ cat tst.awk
BEGIN { FS=OFS=":" }
NR>1 {
    time = substr($1,1,11)
    totIds[time] += 0
    if ( gsub(/[][ ]/,"",$2) ) {
        totIds[time] += split($2,ids,/,/)
        for ( i in ids ) {
            if ( !seen[time,ids[i]]++ ) {
                numUnq[time]++
            }
        }
    }
}
END {
    for ( time in totIds ) {
        print time, ( type ~ /^tot/ ? totIds[time] : numUnq[time]+0 )
    }
}

$ awk -v type='tot' -f tst.awk file
20160420084:0
20160420085:26
20160420090:5

$ awk -v type='unq' -f tst.awk file
20160420084:0
20160420085:19
20160420090:5

答え2

$ cat summarise.pl
#!/usr/bin/perl

use strict;
use List::Util qw(sum0); # useful function to sum elements of array

# handle command-line options
use Getopt::Long qw(VersionMessage :config gnu_getopt);
use Pod::Usage;
$main::VERSION='0.0-alpha';
my $help = 0;
my $type;
GetOptions('total|sum|s|t' => sub { $type .=  't' },
           'unique|u'      => sub { $type .=  'u' },
           'both|b'        => sub { $type  = 'tu' },
           'help|h|?'      => \$help,
           'version|V'     => sub { VersionMessage() },
          ) or pod2usage(2);
pod2usage(-exitval => 0, -verbose => 2) if $help or (! @ARGV && -t);
$type = 'b' if length($type) > 1;
$type = 'u' if length($type) == 0; # default is unique

# Hash-of-Hashes (HoH) to hold timestamps, ids, and id counts.
# Primary key will be timestamp, secondary keys are the IDs,
# and values are the counts of each secondary key.
my %timestamps;

# read and process input file
while(<<>>) {
  next if ($. == 1); # skip first line of input file(s)
  chomp;

  # remove square brackets and spaces from input line
  s/[][]|\s+//g;

  # split current line on colon and commas
  my($ts,@ids) = split /[:,]/;
  $ts = substr($ts,0,11);
  $timestamps{$ts} = () unless (defined $timestamps{$ts});

  # remove non-numeric elements of @ids array
  @ids = grep { /^\d+$/ } @ids;

  # Convert to the HoH structure.
  map { $timestamps{$ts}{$_}++ } @ids;

  close(ARGV) if eof; # reset line counter $. at end of each input file
}

# all input has been processed, so print the results.
foreach my $ts (sort keys %timestamps) {
  my $u = scalar keys %{ $timestamps{$ts} };
  my $s = sum0 values %{ $timestamps{$ts} };

  if ($type eq 'u') {
    printf "%s: %i\n", $ts, $u;
  } elsif ($type eq 't') {
    printf "%s: %i\n", $ts, $s;
  } elsif ($type eq 'b') {
    printf "%s: %i, %i\n", $ts, $u, $s;
  };
}

__END__

=head1 summarise.pl

Script for counting and summarising Numbers & Unique numbers in each line.

=head1 SYNOPSIS

summarise.pl [options] [file ...]

=head1 OPTIONS

=over

=item B<--total>

print total number of IDs per timestamp

=item B<--unique>

print number of unique IDs per timestamp

=item B<--both>

print both unique and total number of IDs

=item B<--version>

Print script's version and exit

=item B<--help>

Print this help message and exit

=back
=cut

メモ:リスト::ユーティリティフォード::使用法Getopt::長いどちらもコア Perl モジュールであり、Perl に含まれています。

perldoc podPerlの「Plain Old Documentation」組み込みコード文書の動作方法の詳細については、参考資料を参照してください。私はその機能の表面だけを傷つけただけです。

出力例:

$ ./summarise.pl input.txt 
20160420084: 0
20160420085: 19
20160420090: 5

$ ./summarise.pl input.txt -t
20160420084: 0
20160420085: 26
20160420090: 5

$ ./summarise.pl input.txt -b
20160420084: 0, 0
20160420085: 19, 26
20160420090: 5, 5

$ ./summarise.pl  --version
./summarise.pl version 0.0-alpha
(Getopt::Long::GetOptions version 2.51; Perl version 5.32.1)

$ ./summarise.pl  --help
summarise.pl
    Script for counting and summarising Numbers & Unique numbers in each
    line.

SYNOPSIS
    summarise.pl [options] [file ...]

OPTIONS
    --total, --sum, -t, -s
        print total number of IDs per timestamp

    --unique, -u
        print number of unique IDs per timestamp

    --both, -b
        print both unique and total number of IDs

    --version, -V
        Print script's version and exit

    --help, -h, -?
        Print this help message and exit

getopt_long()ちなみに、Cプログラムで使用される多くのGNU関数と同様に、PerlGetopt::Longモジュールはオプションの略語を理解しています。たとえば--uni、、--uniqなどはまたはと同じように処理されます-un。省略形がオプション名と明確に一致するのに十分長い場合に機能します。-u--unique


%timestampsそして、ハッシュデータ構造が「どのように見えるか」を知りたい場合:

{
  "20160420084" => undef,
  "20160420085" => { 
     105618372 => 1, 111295547 => 1, 111344871 => 1, 111352520 => 1, 111379566 => 1,
     111394583 => 1, 111412662 => 1, 111413225 => 2, 111413281 => 2, 111413356 => 1,
     111413432 => 2, 111413557 => 1, 111557948 => 2, 111557953 => 1, 111633904 => 2,
     111646835 => 1, 111783178 => 1, 111783198 => 2, 111792767 => 2,
  },
  "20160420090" => {
     111295547 => 1, 111344871 => 1, 111352520 => 1, 111379566 => 1, 111394583 => 1
  },
}

ハッシュのハッシュは、各要素がハッシュである可能性がある連想配列(「ハッシュ」)です。

perldoc perldscPerlデータ構造の詳細については、参考資料を参照してください。

関連情報