【问题标题】:How to finding intervals based on matching elements in perl.?如何根据 perl. 中的匹配元素查找间隔?
【发布时间】:2015-01-09 01:43:36
【问题描述】:
@t = qw(a b c d e + g h + j k m n l + h +);
@q = qw(a b c d e f g h i j k l m l j h h);
@s = qw(a b c d e f g h k j k l m l j h h);

foreach (0..$#q){

  if($t[$_] eq ($q[$_] && $s[$_])){
   print "$t[$_]";
   }
print "$t[$_]-$t[$_]\n";

   elsif($t[$_] eq '+' && $q[$_] eq $s[$_]){
    print"$t[$_]";
   }
   else{
   print "\n";
   }
  }

预期输出:

abcde+gh  [1-8]
jk        [10-11]

l+h+      [14-17]

此处@t 基于匹配@q@s,并打印同样基于@t 的区间。 我无法获得不匹配的间隔。请给我一个好的解决方案

【问题讨论】:

  • “f”如何匹配“+”?
  • @q@s' both have a same elements that possible match "+" in @t. If it is mismatched both @q` 和 @s 未打印,用于计算间隔。
  • 语法错误:elsif without if ..
  • 我得到了左侧输出。我的问题是不能采取右侧间隔。
  • 您上次的编辑引入了语法错误。此外,第一个 if 分支的条件可能不符合您的要求。它比较$t[$_] with $q[$_]`如果$q[$_] 有一个假值,否则它比较$s[$_]

标签: perl


【解决方案1】:

您的代码存在您在第四次编辑时引入的语法错误。您不能将任何代码放在if 的块及其elseif 之外。如果我理解正确,您想知道数组@q@s@t 何时排列,其中@t 允许将'+' 作为通配符。

这是一种解决方案。它使用$start 变量来检查我们是否在一个区间内并存储开始。如果我们处于区间或数组的末尾。我们打印间隔长度。可能有更好的方法来格式化它。最好的办法是引入更复杂的临时对象。如果您对间隔开始和结束的索引不感兴趣,代码会容易得多。

对于测试:我对其进行了一些重组。此外,如果您已经知道$q[$_] eq $s[$_],则不必同时检查$t[$_] eq $s[$_]$t[$_] eq $q[$_]$t[$_] eq "+"

#!/usr/bin/env perl

use strict;   # These aren't optional!
use warnings; # Always use them!
use 5.01;     # for the // operator and say

my @t = qw(a b c d e + g h + j k m n l + h +);
my @q = qw(a b c d e f g h i j k l m l j h h);
my @s = qw(a b c d e f g h k j k l m l j h h);

my ($start);
sub print_interval{
  my $end = shift;
  printf((' 'x(8+$start-$end)). # inserting the whitespaces
     "[%2d-%-2d]\n", $start, $end);
}

foreach (0..$#q){
  my ($te, $qe, $se) = ($t[$_], $q[$_], $s[$_]); # just shorthands
  if($qe eq $se && ($te eq "+" || $te eq $qe)){
    $start //= $_; # if not set, set it to the current index
    print $te;
  }elsif (defined $start){
    print_interval($_-1);
    undef $start;
  }
}

if (defined $start){
  # if we are still in an interval at the end,
  #  we'll have to print that too.
  print_interval($#q)
}

如果您对定义检查不满意,您也可以将$start 设置为-1 并检查0 <= $start

这是一个使用中间对象并将结果保存在数组中的解决方案,这样可以更好地格式化并且代码结构更好:

# … strict, warnings, array declarations
my ($res,@results);

foreach (0..$#q){
  my ($te, $qe, $se) = ($t[$_], $q[$_], $s[$_]);
  if($qe eq $se && ($te eq "+" || $te eq $qe)){
    $res = {start => $_, string => ''} unless defined $res;
    $res->{string} .= $te;
  }elsif (defined $res){
    $res->{end} = $_-1;
    push @results, $res;
    undef $res;
  }
}
if (defined $res){ # still in interval
  $res->{end} = $#q;
  push @results, $res;
}

printf "%-9s[%2d-%-2d]\n", @{$_}{qw|string start end|} for @results;

【讨论】:

  • J.S.你能解释一下你的代码吗,我看不懂。
  • @Subuvan.S Shure 问题出在哪里?第 2 和第 3 段应该解释它。 if 块适用于您在区间内的情况。 elsif 块在您刚离开时被调用(仍然定义了 $start)。在循环之后,您检查您是否仍在区间内。
【解决方案2】:
#!/usr/bin/perl

use strict;
use warnings;

my @t = qw(a b c d e + g h + j k m n l + h +);
my @q = qw(a b c d e f g h i j k l m l j h h);
my @s = qw(a b c d e f g h k j k l m l j h h);

my @current_interval = (); #will store the interval we are currently working on
my @intervals = (); #keeps track of all those intervals

for(0 .. $#t){
    if($q[$_] eq $s[$_] and ($q[$_] eq $t[$_] or $t[$_] eq '+')){
        push(@current_interval, $_);
    }
    else{
        if(@current_interval){
            push(@intervals, [$current_interval[0], $current_interval[$#current_interval]]);    
            @current_interval = ();
        }
    }
}
#when exiting the loop we dont want to lose our current interval!
if(@current_interval){
push(@intervals, [$current_interval[0], $current_interval[$#current_interval]]);}   

#print intervals
for (@intervals){
    my @c = @{$_};
    print $c[0],"\t",$c[1],"\n";
}

我为你准备好了间隔。 请注意,在将此解决方案添加到您的项目之前,我添加了“使用严格;使用警告”。

你好,蒂姆

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-19
    • 2018-03-04
    • 2020-06-01
    • 2020-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多