如何不将现有记录插入哈希

时间:2018-07-20 14:59:12

标签: perl

我正在从日志文件中提取数据,并希望将数据插入哈希中。我的问题是散列具有重复的值,我无法弄清楚如何忽略已经存在的值。我的代码如下:

ReservedNames

输出看起来像这样:

type ReservedNames = "this" | "that"
type FooName = Exclude<string, ReservedNames>;
const f1 : FooName = "This" // Works
const f2 : FooName = "this" // Should error


function withName<T extends string>(v: T & (T extends ReservedNames ? "Value is reserved!": {})) {
  return v;
}

withName("this"); // Type '"this"' is not assignable to type '"Value is reserved!"'.
withName("This") // ok

如何从哈希表中删除这些重复项?预先感谢。

4 个答案:

答案 0 :(得分:3)

如果您不关心时间戳的顺序,请使用哈希引用而不是数组。

while(my $line = <$fh> ) {
    $line =~ /^\s*([\d.]+) ([\d:]+) --- (.*) -.*\s*$/;
    my $timestamp = join(" ", $1, $2);
    my $action = $3;

    # use a counting hash instead of a list
    $results{$action}->{$timestamp}++;
}

您的结构现在有所不同。

'Start Ermittlung der Freibeträge Gesamt.' => {
    '01.06.2018 03:54:49' => 4,
    '07.06.2018 03:14:45' => 4,
    '31.05.2018 03:28:45' => 4,
    '08.06.2018 03:33:36' => 4,
    '02.06.2018 03:30:11' => 4,
},

要访问时间戳,您需要使用keys

say for sort keys %{ $results{$action} };

当然,由于德国日期是DD.MM.YYYY而不是YYYY-MM-DD,因此排序错误。但是您应该使用sort,因为哈希顺序在设计上是不可靠的,因此每次运行的程序都会为您提供随机排列的输出。

答案 1 :(得分:0)

由于时间戳是有序的,

while(my $line = <$fh> ) {
    my ($ts, $action) = $line =~ /^\s*([\d.]+ [\d:]+) --- (.*) -/;

    my $actions = $results{$action} //= [];
    push @$actions, $ts
        if !@$actions
        || $actions->[-1] ne $ts;
}

如果我误以为要订购的时间戳记,这是一种替代方法。

哈希不仅可用于分组;它们对于删除重复项也很有用。以下是删除重复项的惯用方式(在保留顺序的同时):

my %seen;
@a = grep { !$seen{$_}++ } @a;

您可以按如下所示将此方法应用于您的解决方案:

my %seen;
my %results;
while(my $line = <$fh> ) {
    my ($ts, $action) = $line =~ /^\s*([\d.]+ [\d:]+) --- (.*) -/;

    push @{ $results{$action} }, $ts
       if !$seen{$action}{$ts}++;
}

答案 2 :(得分:0)

尝试一下:

while(my $line=<F>) {
        # logfile pattern 31.05.2018 03:25:50 --- Start Deaktiviere PKonten ---
        $line =~ /^\s*([\d.]+) ([\d:]+) --- (.*) -.*\s*$/;
        $timestamp=join(" ",$1,$2);
        $action=$3;

        my $value_in_array = grep {$_ eq $timestamp} @{$results{$action}};

        push(@{$results{$action}} ,$timestamp) 
           unless($value_in_array) ;
}

答案 3 :(得分:-1)

如果要从数组引用中删除重复项,则可以采用这种方法。在建立散列后,它将删除重复项。

while(my $line=<F>) {
    # logfile pattern 31.05.2018 03:25:50 --- Start Deaktiviere PKonten ---
    $line =~ /^\s*([\d.]+) ([\d:]+) --- (.*) -.*\s*$/;
    $timestamp=join(" ",$1,$2);
    $action=$3;
    push @{$results{$action}} ,$timestamp;
}
foreach my $key (keys %result) {
    $result{$key} = [keys %{ {map {$_ => 1} @{$result{$key}}} }];
}

此解决方案应在构建散列时过滤数据:

my %filter;
while(my $line=<F>) {
    # logfile pattern 31.05.2018 03:25:50 --- Start Deaktiviere PKonten ---
    $line =~ /^\s*([\d.]+) ([\d:]+) --- (.*) -.*\s*$/;
    $timestamp=join(" ",$1,$2);
    $action=$3;
    if(!defined $filter{$action}{$timestamp}) {
        push @{$results{$action}} ,$timestamp;
        $filter{$action}{$timestamp} = 1;
    }
}