Perl帮助
我有一个复杂的实用程序(让我们简称为KIP) 我是从AWK转换为perl。 AWK有一个双重联系的设施 我用过的清单。这很有效,但我无法弄清楚该怎么做 这在perl中。我知道FIFO链表是一个很好的解决方案。
KIP功能(如果您有兴趣) KIP从文档中删除重复的项目。 AWK计划的方式 工作是它扫描文档寻找重复的项目和 构建一个数组,显示" real"项目及其所有重复项。一世 需要一个FIFO链表到重复项,如下所示:
PICTORIAL OF THE FUNCTION
REAL
ITEM ARRAY OF $POINTER[] LINKED LIST
NUMBER
+-------------+---------+ +---------------+ +---------------+
1 | real item 1 | ------> | |dup_1_of_item_1|-->|dup_n_of_item_1|
+-------------+---------+ +---------------+ +---------------+
+-------------+---------+ +---------------+ +---------------+
2 | real item 2 | ------> | |dup_1_of_item_2|-->|dup_n_of_item_2|
+-------------+---------+ +---------------+ +---------------+
+-------------+---------+ +---------------+ +---------------+
3 | real item 3 | ------> | |dup_1_of_item_3|-->|dup_n_of_item_3|
+-------------+---------+ +---------------+ +---------------+
... ...
KIP将运行"真实项目n"数组来处理每个真实项目。去做 所以,KIP将运行链表链以删除重复的项目 从文件。推送重复的东西会很好 "真实项目1"到堆栈并保存堆栈地址以供日后使用。然后, 之后,KIP可以访问保存的堆栈地址并关闭项目。
我知道这是我对perl缺乏了解,但我很难过 实现这样的指针数组结构。我认为推和流行 应该工作,但要么语法错误,要么它只是不起作用 我
这是我发现的难点 -
我需要创建可以将信息推送到的动态堆栈。
堆栈将在KIP的不同部分访问,所以我需要 将堆栈地址保存在数组中以供日后使用。
堆栈是动态构建的(不是使用QW构建的数组 所有文件似乎都在描述。)
我需要大量的堆栈(每个real_item都有一个堆栈 复制)。
有人能指点我吗?任何相关信息都将是 赞赏。
TIA
在这'我做了什么;
ADD ITEMS TO STACK
# $IDX_ori_iSub - subscript for the real item
# $IDX_dup_iSub - subscript for each duplicate item that is
# found
# populate the fields for the stack
$MsgID = $IDXMsgID[$IDX_dup_iSub];
$LineNumber = $IDXLineNumber[$IDX_dup_iSub];
$Offset = $IDXOffset[$IDX_dup_iSub];
$LineCount = $IDXLineCount[$IDX_dup_iSub];
$KCount = $IDXKCount[$IDX_dup_iSub];
# set up stack
my @stackOfDuplicates;
# Save the address of the stack for later access
if ( $IDXChain[$IDX_ori_iSub] == 0)
{
$IDXChain[$IDX_ori_iSub] = \@stackOfDuplicates;
}
# Push items onto list.
push @stackOfDuplicates, $MsgID ;
push @stackOfDuplicates, $LineNumber ;
push @stackOfDuplicates, $Offset ;
push @stackOfDuplicates, $LineCount ;
push @stackOfDuplicates, $KCount ;
从堆栈中删除物品
my @stackOfDuplicates = $IDXChain[$IDX_iSub];
if ( @stackOfDuplicates )
{
# Remove first items from list.
my $MsgID = shift @stackOfDuplicates;
my $LineNumber = shift @stackOfDuplicates;
my $Offset = shift @stackOfDuplicates;
my $LineCount = shift @stackOfDuplicates;
my $KCount = shift @stackOfDuplicates;
print " \$MsgID = $MsgID";
print " \$LineNumber = $LineNumber";
print " \$Offset = $Offset";
print " \$LineCount = $LineCount";
print " \$KCount = $KCount";
}
结果的典型结果我很快就看到了
$MsgID = ARRAY(0x2b786c0)
Use of uninitialized value $LineNumber in concatenation (.) or string
$LineNumber =
Use of uninitialized value $Offset in concatenation (.) or string at
$Offset =
Use of uninitialized value $LineCount in concatenation (.) or string
$LineCount =
Use of uninitialized value $KCount in concatenation (.) or string at
$KCount =
答案 0 :(得分:1)
不是恢复重复堆栈以准备删除,而是将地址作为第一个元素输入。然后最后的打印得到第一个变量是数组引用,因为这是@stackOfDuplicates
下唯一的事情,其他变量没有得到任何结果(最终undef
),{{{ 1}}已打印。
在Perl中分配对数组的引用不会恢复数组(与该引用相关联),它不是像在C中那样指向第一个数组地址的指针。相反,此时新数组是已创建并且该引用成为其第一个元素。
要从引用中获取数组,我们需要取消引用它
Use of unitialized ...
或者,可能更清楚
my @stackOfDuplicates = @{ $IDXChain[$IDX_iSub] };
我认为您的数据结构没有任何问题。在Perl my $ref_stackOfDuplicates = $IDXChain[$IDX_iSub];
my @stackOfDuplicates = @$ref_stackOfDuplicates;
确实由数组实现,而FIFO
+ push
(或shift
+ push
用于堆栈)。
答案 1 :(得分:0)
你的重复堆栈实际上是一堆"有关重复的详细信息"。这使事情变得非常复杂。我怀疑你宁愿做一个小小的调整来修复你已经拥有的东西,但你会更好地退一步,做一些研究,然后再进行一次。
整个操作的关键是收集描述一个"重复项目的属性"或"原始项目"成为一个关联数组 - 即一个事实上的对象。更好的是,Mo.pm是一个极简主义的Perl模块,可以为您提供基本对象。
如果您无法安装模块,或者如果您没有正式安装模块的管理员权限,则可以复制these three lines并将其放入名为 Mo的文件中。 pm 与您的脚本位于同一目录,然后您就可以了。
您还需要在同一目录中创建另一个名为 DocItem.pm 的文件,该文件将定义您的DocItem类。将以下内容放入其中:
package DocItem;
use Mo;
has MsgID => ();
has LineNumber => ();
has Offset => ();
has LineCount => ();
has KCount => ();
现在你有一个课程,你可以"拉入"你的脚本。您的代码应如下所示:
#!/usr/bin/env perl
use DocItem;
my @stack ;
my @problem ;
# Have to create an "original" and some duplicates by making
# up the attributes that define each item
my $original = DocItem->new(
MsgID => "id14" ,
LineNumber => 126 , # All these made up
Offset => 17 ,
LineCount => 64 ,
KCount => 1237 ,
);
print "MsgID: ", $original->MsgID, "\n"; # How you access an attribute
print "LineCount: ", $original->LineCount;
print " ==> ";
$original->LineCount(8600); # How you set an attribute after object creation
print $original->LineCount, "\n";
$problem[0] = $original ; # NOTE: make the DocItem called "$original" the
# first item of the array @problem.
# Using a loop to make-up 4 DocItem objects representing 4 duplicates
for (1 .. 4) {
my $id = "id" . $_ ; # All these attributes made up
my $line = 12 * $_ ; # values based on the loop variable
my $off = 18 + $_ ;
my $Lcnt = 126 + $_ ;
my $KC = 1000 - $_ ;
# Create a new DocItem representing one duplicate
my $duplicate = DocItem->new(
MsgID => $id ,
LineNumber => $line ,
Offset => $off ,
LineCount => $Lcnt ,
KCount => $KC ,
);
# NOTE: push the DocItem called "$duplicate" onto the problem array
# This builds up a structure representing one "horizontal line" of your pic
push @problem, $duplicate;
}
# The four "pushes" (one for each loop iteration) leaves @problem looking like:
# $problem[0] $problem[1] $problem[2] $problem[3] $problem[4]
# =========== =========== =========== =========== ===========
# MsgID: id14 MsgID: id1 MsgID: id2 MsgID: id3 MsgID: id4
# Offset: 17 Offset: 19 Offset: 20 Offset: 21 Offset: 22
# KCount: 1237 KCount: 999 KCount: 998 KCount: 997 KCount: 996
# (etc for LineNumber and LineCount)
# Now, push the whole problem array into slot 0 of @stack
push @stack, \@problem; # Or, $stack[0] = \@problem ;
# In a similar way, build up more arrays representing "problems" each
# with the "original" DocItem in slot 0 and the duplicate DocItems in
# successive slots of the array, and again, push the whole lot onto @stack
# and then....
my $first_problem = shift @stack;
my $first_original = shift @$first_problem; # Note, this access is required because
# $first_problem holds a reference to an
while (my $dup = shift @$first_problem) { # array, not an array;
# $dup holds one DocItem object representing
# a duplicate and $first_original holds the
# DocItem representing the orignal.
# Do what you need to do
}
每个@problem
代表上图中的一条水平线。第一个插槽 - $problem[0]
- 保存您的原始和后续重复项被推送到阵列上。然后通过引用问题数组@stack
\@problem
上
然后你可以遍历你的堆栈,转移一个完整的问题,移开原来的,然后迭代处理它们的重复项。
Gabor Szabo的优秀教程Read this帮助保持"推动"," pop"," shift"并且"未移位"直。