【问题标题】:Perl count for matching strings in an arrayPerl 计数匹配数组中的字符串
【发布时间】:2015-09-29 02:56:08
【问题描述】:

我有一个用字符串填充的数组。我想检查一个特定的字符串在这个数组中是否不止一次,然后打印一个错误警告。

我使用 List::MoreUtils: 中的 true 方法来计算我的匹配项。 在我的数组中,我有一些字符串,它们的子字符串与同一数组中的其他字符串相同。
因此,如果我检查同一字符串是否在数组中多次出现,我会收到错误警告,即使可能只有另一个字符串具有相同的子字符串。 我尝试通过将字符串长度添加为模式来解决问题(因此字符串和长度必须相等才能弹出错误消息),但这也不起作用。
我的代码如下所示:

use strict;
use warnings;
use List::MoreUtils 'true';

my @list = ("one", "two", "three", "onefour", "one");

foreach my $f (@list) {  

        my $length = length($f);
        my $count = true { $length && "$f"} @list;

           if($count > 1) {
                    print "Error with: ", $f, " counted ", $count, " times!\n";
                }
       $count = 0;
    }

使用此代码,我根本不会收到错误警告,即使“一”在数组中出现了两次。如果我不包含长度作为 true 方法的模式,那么字符串“one”将被计算 3 次。

【问题讨论】:

  • 您是否只是在“一个”被报告为骗子之后?例如。不是子串匹配?

标签: arrays string perl


【解决方案1】:

我不会为此使用true - 看起来您正在尝试做的是“挑选”重复项,而不关心子字符串。

my %seen;
$seen{$_}++ for @list; 
print grep { $seen{$_} > 1 } @list; 

所以要复制你的测试:

my %count_of;
$count_of{$_}++ for @list;  
foreach my $duplicate (  grep { $count_of{$_} > 1 } @list ) {
    print "Error: $duplicate was seen $count_of{$duplicate} time\n";
}

【讨论】:

  • 我不想“挑出”重复项。如果数组中有重复项,我想打印一条错误消息,而不是更改数组/擦除重复项!
  • 这不会修改您的数组 - grep 创建一个您打印的“新”数组。我添加了一个我认为可以满足您需求的 sn-p?
  • 很抱歉回答迟了。您的回答非常好,解决了我的问题!非常感谢;)
【解决方案2】:

你实际上没有匹配任何东西。我在您的代码中添加了调试输出。

my @list = ( "one", "two", "three", "onefour", "one" );

foreach my $f (@list) {
    say "f: $f";
    my $length = length($f);
    say "length: $length";
    say "true { $length && $f} $_: " . ( $length && "$f" ) for @list;
    my $count = true { $length && "$f" } @list;
    say "count: $count";

    if ( $count > 1 ) {
        print "Error with: ", $f, " counted ", $count, " times!\n";
    }
    $count = 0;
}

我们来看看:

f: one
length: 3
true { 3 && one} one: one
true { 3 && one} two: one
true { 3 && one} three: one
true { 3 && one} onefour: one
true { 3 && one} one: one
count: 5
Error with: one counted 5 times!
f: two
length: 3
true { 3 && two} one: two
true { 3 && two} two: two
true { 3 && two} three: two
true { 3 && two} onefour: two
true { 3 && two} one: two
count: 5
Error with: two counted 5 times!
f: three
length: 5
true { 5 && three} one: three
true { 5 && three} two: three
true { 5 && three} three: three
true { 5 && three} onefour: three
true { 5 && three} one: three
count: 5
Error with: three counted 5 times!
f: onefour
length: 7
true { 7 && onefour} one: onefour
true { 7 && onefour} two: onefour
true { 7 && onefour} three: onefour
true { 7 && onefour} onefour: onefour
true { 7 && onefour} one: onefour
count: 5
Error with: onefour counted 5 times!
f: one
length: 3
true { 3 && one} one: one
true { 3 && one} two: one
true { 3 && one} three: one
true { 3 && one} onefour: one
true { 3 && one} one: one
count: 5
Error with: one counted 5 times!

所以你总是有字符串$f 的长度,它大于0,因此在Perl 中计算为true。然后你有$f。这也是true,因为所有不是空字符串('')的字符串都是真的。

您使用true 函数遍历@list 中的所有元素。该块始终为真。所以你总能得到@list中元素的数量。


如果你只想去除重复出现的次数,你可以使用哈希来计算它们。

my %count;
$count{$_}++ for @list;
my @unique = keys %count; # unsorted
# see Sobrique's answer with grep for sorted the same way as before

那么List::MoreUtils中还有uniq

my @unique = uniq @list;

如果你想知道每个元素是否是 any 其他元素的子字符串,你可以使用Perl's builtin index,它可以找到一个字符串在另一个字符串中的位置,以及一个@987654338 @。

foreach my $f (@list) {
    if ( my @matches = grep { $_ ne $f && index( $_, $f ) > -1 } @list ) {
        warn "$f is a substr of: @matches";    # will auto-join on $,
    }
}

__END__

one is a substr of: onefour at /code/scratch.pl line 91.
one is a substr of: onefour at /code/scratch.pl line 91.

当然,由于ne,这并不能说明元素 0 和 4 都是“一”。请注意,如果根本没有匹配项,index 将返回 -1


编辑your comment on Sobrique's answer之后:

要仅在存在重复项(或 substr 重复项)时获得警告,只需对它们进行计数。任何地方都没有修改:

my @list = ( "one", "two", "three", "onefour", "one" );

my %count;
$count{$_}++ for @list;
warn sprintf 'Number of duplicates: %d', @list - keys %count if @list != keys %count;

my $count_substr;
foreach my $f (@list) {
    $count_substr++
        if grep { $_ ne $f && index( $_, $f ) > -1 } @list;
}
warn sprintf 'Number of substring duplicates: %d', $count_substr if $count_substr;

【讨论】:

  • 总共是一个更全面的答案。我认为我们已经得出了类似的结论,即 true 并不是真正适合使用的东西。
  • 谢谢@Sobrique。 :) 你有没有注意到我们的名字看起来很相似?这总是让我毛骨悚然。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-24
  • 2014-08-18
  • 2012-12-30
  • 1970-01-01
  • 2015-08-10
  • 2021-05-14
相关资源
最近更新 更多