如何使用map清理此Perl代码?

asc*_*ltz 2 perl

下面的代码完成了我想要的.它打印列表并在不连续的行的末尾添加星号,例如,如果您从1跳到3或从3跳到5.

use strict;
use warnings;
#note: thanks to all who helped with formatting issues.

#note: I recognize a hash would be a much better option for what I want to do.
my @printy = ("1 -> this",
  "5 -> that",
  "3 -> the other",
  "6 -> thus and such");
@printy = sort {num($a) <=> num($b)} @printy;

my $thisID = 0;
my $lastID = 0; 

#print out (line)* if initial number is >1 more than previous, or just (line) otherwise
for (@printy)
{ 
$thisID = $_; $thisID =~s/ .*//g;
if ($thisID - $lastID != 1) { $_ =~ s/$/ \*/; }
$lastID = $thisID;
}
print join("\n", @printy) . "\n";

sub num
{
  my $x = $_[0];
  $x =~ s/ .*//;
  return $x;
}
Run Code Online (Sandbox Code Playgroud)

但我认为我可以做得更好.感觉很纠结,我的直觉告诉我,我错过了一些能够更容易完成工作的强大功能,可能需要两行.

现在我以前使用过该map()命令,但只是查看/修改一个元素,而不是它与前一个元素的比较.任何人都可以推荐一种方法来使这更简洁吗?谢谢!

Zai*_*aid 7

由于Perl推广TIMTOWTDI,起初map看起来似乎是一个很有吸引力的选择.让我们看看它如何为这项任务付出代价:


施瓦茨安思想过程

  1. 由于访问相邻元素是必要的,因此使用索引很方便.因为对于n元素,有n-1成对的邻居,你不必循环n时间.在这种情况下,让我们从1通常开始0:

    1 .. $#printy
    
    Run Code Online (Sandbox Code Playgroud)
  2. 可以通过调用内部的相关索引来访问相邻元素map.

    map { my $prev = $printy[$_-1]; my $curr = $printy[$_] } 1 .. $#printy;
    
    Run Code Online (Sandbox Code Playgroud)

    数组切片更简洁地表达了这一点:

    map { my ( $prev, $curr ) = @printy[$_-1,$_]; } 1 .. $#printy;
    
    Run Code Online (Sandbox Code Playgroud)
  3. 让我们介绍使用num子程序比较数字的真实逻辑:

    map {
           my ( $prev, $curr ) = @printy[$_-1,$_];
           if ( num($curr) - num($prev) > 1 ) {
              "$curr *";
           }
           else {
              $curr;
           }
        } 1 .. $#printy;
    
    Run Code Online (Sandbox Code Playgroud)

    这相当于:

    map {
           my ( $prev, $curr ) = @printy[$_-1,$_];
           $curr .= " *" if num($curr) - num($prev) > 1;
           $curr
        } 1 .. $#printy;
    
    Run Code Online (Sandbox Code Playgroud)
  4. 记住不要忘记第一个元素:

    @printy = ( $printy[0],
                map {
                       my ( $prev, $curr ) = @printy[$_-1,$_];
                       $curr .= " *" if num($curr) - num($prev) > 1;
                       $curr
                    } 1 .. $#printy
              );
    
    Run Code Online (Sandbox Code Playgroud)

鉴于最终结果,我不太确定我会用到map这个:

  • 这很难读
  • 有很多事情要发生
  • 下一个处理代码的人会爱你

  • @Borodin 1)当然这是回答这个问题的真正尝试.为什么它会是什么呢?2)我鼓励(重新)阅读[OP的评论](http://stackoverflow.com/questions/40997876/how-can-i-use-map-to-clean-up-this-perl-code/ 40998309?noredirect = 1个#comment69209139_40998309).他们赞赏*"原始方法[不必]是花哨的"*3)施瓦茨变换如果使用得当,可能是一个好主意 (6认同)
  • 随着时间的推移,我学会了用任何"地图"处理两个以上的语句作为代码气味.最好在新需求在代码中找到方法之前将其重写为`for`循环:) (4认同)
  • @Borodin这个答案不是给OP一条鱼,而是教他们如何钓鱼.他们认为`map`会有所帮助,我想让他们了解为什么它可能不是他们认为/认为它是魔法子弹的原因.*"我不太确定......"*评论贯穿了这一思路,这就是为什么它最终会作为结论出现的原因. (4认同)
  • 我完全同意.但是在循环中进行Schwartzian变换也很长.我认为这是为了在初学者易于阅读和为专业人士阅读难以阅读之间找到妥协.这实际上取决于它是什么,但有一段时间我会选择更短,更简洁的版本并添加解释性注释,然后希望下一个人(或未来的我)将从中学到一些东西.:d (2认同)
  • @Zaid我也会对那些对你的回答低估的人感到惊讶.我不知道Schwartzian变换,这对我来说很有教育意义,我很高兴知道我原来的方法不需要花哨S (2认同)