尽管您接受了0%的问题(提高这个数字是非常公平的),但这里是对您的代码的分析,以便您下次可以编写更好(和工作)的 Perl。
关于编写 Perl 的一般评论
纪律与混乱
总是use strict
和use warnings
,尤其是当您试图找出脚本不工作的原因或当您是 Perl 新手时。通常,这些 pragma 会提醒您每个人偶尔会犯的最愚蠢的错误。
Perl 不会强迫您编写好的代码(和 TIM TOWDTY),但大多数时候您应该坚持使用strict
Perl 的子集,除非您有充分的理由。
使用strict
意味着您必须使用 声明所有变量my
,除非您有充分的理由。我认为声明变量是一件好事。
Perl 不是 C
大多数内置函数不需要括号来分隔它们的参数。即split(/ /, $check)
和split / /, $check
在大多数情况下都是一样的。
此外,Perl 很少需要for(INIT; COMPARE; INCREMENT)
循环结构,尤其是当最后一部分是$i++
. 相反,您可以使用foreach
-syntax 和range:
for my $i ($MIN .. $MAX)
为什么你的代码不起作用
还有:有什么不好的成语可以避免
我已经指出,所有变量都应该声明为,my
并且有更好的循环语法可用。
@file2 = @file // full content of the file in an array
//
不引入评论。它是定义或运算符。此外,此语句不会以;
. 这会使 Perl 感到困惑,因为下面的for
循环是同一语句的一部分——但这是无效的。
此外,您不会更改@file2
or的内容@file
,因此不需要进行复制。
$temp = $file[$i];
你从不使用$temp
.
@grepNames = grep(/$fields[2]/, @file2);
您可以使用它grep
来找出有多少行包含相同的变量名称。当您稍后再次遍历所有元素时,这是多余的。@file
if($#grepNames >= 1)
你写的是问题:最高索引是否@grepNames
大于或等于1?而你可能是说我们有不止一场比赛吗?. 我把它写成
if (@grepNames > 1)
然而,这主要是一种风格上的评论。
if( $file[$i] =~ /INTEGER/ ...
等什么?如果$file[$i]
包含INTEGER
,那么将$check
或$temp
。使用标量而不是数组下标时,您可以节省一些输入。
push(@data, $file[$j]);
@data
即使您已经有一条具有相同变量名的行,您也可以将某些东西推到上面。更糟糕的是,如果@file
包含n 个元素,那么内部for
循环会迭代n - 1 个@data
元素,并且在大多数情况下你会推送一些东西,使你的算法O(n²)
i \ j | INTEGER | Int32 | UInt32
--------+---------+-------+-------
INTEGER | - | j | j
Int32 | i | - | j
UInt32 | i | i | -
这是一个表格,说明(根据您的规则)应该将哪个元素放入@data
. 您可能想将此表与您的if
/ elsif
s 进行比较,并确定是否可能缺少某些情况。
push(@data, $file[j]);
你之前忘记了$
印记j
。
更好的解决方案
您的算法在O(n²)中运行,或者更确切地说是O(n * (2n - 1))。但是,您的问题可以在O(n)中解决。
我将问题视为:
输入中的每一行都有一个标识符和一个相关的权重。
对于输出,从具有相同标识符的所有行的集合中选择具有最小权重的行。如果两条或多条线具有相同的最小权重,则可以选择这些最小线中的任何一条。
一行的权重取决于该行中的第二个单词是什么关键字:
Unsigned32 => 1,
Integer32 => 2,
INTEGER => 3,
如果第二个单词不是这些关键字,则应抛出错误。
每个标识符第一次出现的顺序在输入和输出中都是相同的。
在我的解决方案(如下所示)中,我使用了第一个和第三个单词作为标识符。如果输出中已经存在一条线,如果当前线的权重较低,我会更新它。
编辑:我的解决方案
#!/usr/bin/perl
use strict; use warnings;
my @data;
my %index;
while (<DATA>) {
$_ =~ s/^\s+//;
my @fields = split /\s+/, $_, 3;
@fields = (@fields[0 .. 1], split /(?=\W)/, $fields[2], 2);
my ($class, $type, $name, $rest) = @fields;
if (defined $index{$class}{$name}) {
# we have a predecessor
my $index = $index{$class}{$name};
$data[$index][1] = (sort compareTypes $data[$index][1], $type)[0];
} else {
push @data, \@fields;
$index{$class}{$name} = $#data;
}
}
foreach (@data) {
my @fields = @$_;
print "@fields[0..2]$fields[3]";
}
sub compareTypes {
my %weight = (
Unsigned32 => 1,
Integer32 => 2,
INTEGER => 3,
);
my $weight_a = $weight{$a} // die "undefined type $a";
my $weight_b = $weight{$b} // die "undefined type $b";
return $weight_a <=> $weight_b;
}
__DATA__
typedef INTEGER Id;
typedef Integer32 Id;
typedef Integer32 Id;
typedef Integer32 Id;
typedef INTEGER Identifier;
typedef Integer32 Index;
typedef Unsigned32 Identifier;
typedef Integer32 Index;
typedef Unsigned32 TunnelId;
typedef Unsigned32 TunnelId;
const Unsigned32 maxValue = 65535;
const Integer32 Index_maxValue = 65535;
const Unsigned32 maxValue = 4294967295;
const Unsigned32 Index_maxValue = 65535;
输出:
typedef Integer32 Id;
typedef Unsigned32 Identifier;
typedef Integer32 Index;
typedef Unsigned32 TunnelId;
const Unsigned32 maxValue = 65535;
const Unsigned32 Index_maxValue = 65535;