【问题标题】:How to Create Multiple Stacks?如何创建多个堆栈?
【发布时间】:2016-02-23 21:58:35
【问题描述】:

Perl 帮助

我有一个复杂的实用程序(我们简称为 KIP) 我正在从 AWK 转换为 perl。 AWK 有一个双重链接的设施 我使用的列表。这很好用,但我不知道该怎么做 这在 perl 中。我知道 FIFO 链表是一个很好的解决方案。

KIP 功能(如果您有兴趣) KIP 从文档中删除重复项。 AWK程序的方式 工作原理是它扫描文档以查找重复的项目和 构建一个显示“真实”项目及其所有重复项的数组。一世 需要一个 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 将运行“real item n”数组来处理每个真实项目。去做 因此,KIP 将运行链表链来删除重复项 从文档中。只是推送的副本会很好 将“真正的项目 1”放入堆栈并保存堆栈地址以供以后使用。然后, 之后,KIP 可以访问保存的堆栈地址并弹出项目。

我知道这是我对 perl 的了解不足,但我很难过 实现这样的指针数组结构。我认为推和流行 应该可以工作,但是语法错误或根本不起作用 我。

这就是我发现的困难 -

  1. 我需要创建可以将信息推送到其中的动态堆栈。

  2. 堆栈将在 KIP 的不同部分访问,所以我需要 将堆栈地址保存在数组中以供以后使用。

  3. 堆栈是动态构建的(不是使用 QW 构建的数组 所有文档似乎都有描述)。

  4. 我需要大量堆栈(每个 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 =

【问题讨论】:

  • 总而言之,您正试图从文本文件中删除重复记录?
  • 在 Perl 中,您使用散列(关联数组,其中的键是字符串)来处理这类事情,而不是数组(用整数索引)或链表。大多数时候,数组只是笨拙的。链表很有用,它们可以使用散列来构建,但我不会在这里使用它们。
  • 始终以 use strict; use warnings; 开始您的 Perl 脚本,以便获得正确的编译时错误报告。
  • 查看我认为确定问题的更新帖子。

标签: perl stack singly-linked-list


【解决方案1】:

地址最终作为其第一个元素输入,而不是恢复重复的堆栈以准备删除。然后最后的打印得到第一个变量是数组引用,因为这是@stackOfDuplicates 下唯一的东西,其他变量什么也没有得到(结束undef),Use of unitialized ... 被打印出来。

在 Perl 中分配对数组的引用不会恢复数组(与该引用关联),它不是像在 C 中那样将指针分配给第一个数组地址。相反,此时一个新数组是已创建,并将该引用作为其第一个元素。

要从它的引用中获取一个数组,我们需要取消引用它

my @stackOfDuplicates = @{ $IDXChain[$IDX_iSub] };

或者,可能更清楚

my $ref_stackOfDuplicates = $IDXChain[$IDX_iSub];
my @stackOfDuplicates = @$ref_stackOfDuplicates;

我认为您的数据结构没有任何问题。在 Perl 中,FIFO 确实是由数组和push+shift 实现的(或者push+pop 是堆栈)。

【讨论】:

  • 请阅读How to Answer,了解Stack Overflow 上的最佳答案。用推测的答案回答不清楚的问题对任何人都没有好处。
  • 是的,因为这个问题仍然没有任何好处。充其量,这是一个写得不好且不清楚的问题,不包含minimal reproducible example。在最坏的情况下,它是许多“如何取消引用数组引用?”中的任何一个的副本。问题。
  • @MattJacob 嗯,我不记得最近看到过如此详尽的问题。问题陈述包括 ASCII 绘图以及代码和输出。错误很简单,但 OP 不知道,因此是这个问题。谢谢,我再等一会。我正在删除这些 cmets。
【解决方案2】:

您的重复堆栈实际上是一堆“有关重复的详细信息”。这使事情变得非常复杂。我怀疑你更愿意做一个小的调整来修复你已经拥有的东西,但你最好退后一步,做一些研究,然后再试一次。

整个操作的关键是将描述一个“重复项”或“原始项”的属性收集到一个关联数组中 - 即一个事实上的对象。更好的是,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] - 保存您的原始和后续副本被推送到阵列上。然后可以通过引用您的问题数组\@problem 将整个数组推送到@stack

然后你可以迭代你的堆栈,转移整个问题,转移原始问题,然后迭代处理它们的重复项。

Read this Gabor Szabo 的优秀教程,帮助保持“push”、“pop”、“shift”和“unshift”正常。

【讨论】:

  • 谢谢,但是在一个 25,000 行的程序中,事情太固定了,无法重写或重新开始。我花了一个多星期的时间试图删除所有数百个全局变量,最后放弃了。你是对的,我只是需要调整一下。
  • 我查看了您的代码并且确实了解您所做的事情。我需要在一个特定领域多一点指导。但是 StackOverflow 不允许我问这个问题。
  • Chuck - 如果你想追求它,我可以为你提供一两个小时的帮助 - 有 stackoverflow 聊天室。我的时区是 +11 小时。在你说你不能重新设计它之后我无话可说(我很感激 - 通常它不可能)是现有结构太复杂而无法处理(当然,我只见过一个很小的你正在做的事情的样本,所以我的意见必须从这个角度来看)。
  • RE:您发布的程序 - 我已扩展程序以添加多个“问题”,但是,除非我使用不同的堆栈,否则我无法使我的程序工作。请记住,在我开始转移元素之前,我已经构建了数百个堆栈。所以,我现在需要动态创建堆栈名称。是的,我知道每个人都说不要。每个人都说使用哈希。但是,即使有哈希,我也有同样的问题。你能告诉我如何生成动态命名的数组吗?我已经尝试过这种变体: $temp = 'problem_' 。 $控制; \@问题 = \@{$temp}; $问题[0] = $原始;
  • 问题是数组,其中每个元素都是一个 doc_item。堆栈是一个数组,其中每个元素都是一个数组(即一个问题)。要动态创建堆栈,请动态创建数组 - 为此需要引用(词法)变量。 for (1 .. 10) { my @tmp = generate_array(); $stacks[$_] = \@tmp } 但是现在,这 10 个数组具有整数名称 - 每个数组都由 @stacks 中的索引表示。因此,您需要一个哈希 - 一个数组,其中每个索引都是文本名称而不是整数; while (is_more_data($fh)) { my $name = get_stack_name(); my @tmp = generate_stack($fh); $stacks_hash{ $name } = \@tmp }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-25
相关资源
最近更新 更多