【问题标题】:Remove elements from an array which have a substring that is itself an element of the array从数组中删除具有子字符串的元素,该子字符串本身就是数组的元素
【发布时间】:2019-05-26 02:03:08
【问题描述】:

在 Perl 中,我想从数组中删除所有元素,其中同一数组的另一个元素是所述元素的非空子字符串。

假设我有数组

@itemlist = ("abcde", "ab", "khi", "jklm");

在这种情况下,我希望删除元素 "abcde",因为 "ab""abcde" 的子字符串。

我可以制作数组的副本(也许作为哈希?),迭代它,尝试使用原始数组的每个元素进行索引并删除它,但必须有一个更优雅的方式,不是吗?

感谢您的帮助!

为了清晰起见,稍作编辑。

【问题讨论】:

  • 这上面写满了家庭作业...
  • 这不是家庭作业。有问题的项目应该作为搜索查询中其他项目的同义词,并且由于搜索算法显然会进行完整的子字符串搜索,因此我被要求删除由较短的同义词组成的每个同义词。
  • 您希望处理多大的@itemlist?
  • 我希望里面的物品不会超过 12-15 件。
  • 您会认为obafoobar 的子字符串吗?换句话说,“同义词”是否只是单词的开头,就像缩写一样?

标签: arrays perl


【解决方案1】:

您可以从所有项目中构造一个正则表达式并丢弃任何匹配的内容:

$alternation = join('|', map(quotemeta, @itemlist));
@itemlist = grep !/($alternation).|.($alternation)/, @itemlist;

().|.() 只是确保项目与自身不匹配。

【讨论】:

  • 这似乎奏效了。必须先 lc 整个事情,但那是我的错误,我没有具体说明。谢谢! :)
【解决方案2】:

好吧,我不会称其为优雅,但这里是:

#!usr/bin/perl
use strict;
use warnings;

my @itemlist = ("abcde", "ab", "khi", "jklm");

@itemlist = grep { 
    @itemlist ~~ sub {$_ !~ /(?:.\Q$_[0]\E|\Q$_[0]\E.)/} 
} @itemlist;

print "@itemlist";

它依赖于smart match 的一个相当晦涩的行为:如果左边的参数是一个数组,右边的参数是一个 sub,它会为每个元素调用 sub,只有当 sub 返回 true 时,最终结果才为 true每个元素。

解释:对于数组的每个元素,它检查没有其他元素是该元素的子字符串(需要至少一个额外的字符,以便元素不会匹配自己)。

注意: wdebeaum 的答案可能是我在现实世界中更喜欢的答案。尽管如此,使用智能匹配可以做一些奇怪的事情还是很有趣的。

【讨论】:

  • 也谢谢你。了解到我需要阅读有关智能匹配运算符的更多信息,如果没有别的,它在代码中看起来很酷。 :)
【解决方案3】:

wdebeaum 的答案是使用的解决方案,而不是下面的解决方案,但我通过这样做学到了一些东西,也许其他人也会这样做。在我写完我的之后,我决定在包含数千个元素的列表上对其进行测试。

b.pl:

#!/usr/bin/perl

use strict;
use warnings;

my @itemlist = <>;
for(@itemlist) { chomp; }
my $regex;

if(defined $ENV{wdebeaum}) {
    # wdebeaum's solution
    my $alternation = join('|', map(quotemeta, @itemlist));
    $regex = qr/(?:$alternation).|.(?:$alternation)/;
} else {
    # my solution
    $regex = join "|", map {qq{(?:\Q$_\E.)|(?:.\Q$_\E)}} @itemlist;
}

my @result = grep !/$regex/, @itemlist;
print scalar @itemlist, "\t", scalar @result, "\n";

我生成了一个包含 5000 个随机单词的列表。

sort -R /usr/share/dict/american-english|head -5000 > some-words

对于小型列表,两种解决方案似乎都很好。

$ time head -200 some-words | wdebeaum=1 ./b.pl
200 198

real    0m0.012s
user    0m0.004s
sys     0m0.004s

$ time head -200 some-words | ./b.pl
200 198

real    0m0.068s
user    0m0.060s
sys     0m0.004s

但对于较大的列表,wdebeaum 显然更好。

$ time cat some-words | wdebeaum=1 ./b.pl 
5000    1947

real    0m0.068s
user    0m0.064s
sys     0m0.000s

$ time cat some-words | ./b.pl 
5000    1947

real    0m8.305s
user    0m8.277s
sys     0m0.012s

我认为差异的原因是,即使两个正则表达式具有相同数量的可能路径,我的正则表达式也有更多路径需要尝试,因为它与路径具有相同数量的 .s ,而 wdebebaum 只有两个。

【讨论】:

    【解决方案4】:

    您可以使用哈希来计算所有单词的子字符串。列表中计数高于一个的任何单词都是另一个单词的子字符串。在此示例中,子字符串的最小长度为 2:

    use strict;
    use warnings;
    use feature 'say';
    
    my @list = qw(abcde ab foo foobar de oba cd xs);
    
    my %count;
    
    for my $word (@list) {
        my $len = length $word;
        $count{$word}++;
        for my $start (0 .. $len - 2) {
            for my $long (2 .. $len - 2) {
                my $sub = substr($word, $start, $long);
                $count{$sub}++;
            }
        }
    }
    say for grep $count{$_} == 1, @list;
    

    输出:

    abcde
    foobar
    xs
    

    【讨论】:

      【解决方案5】:

      以下将从数组中删除子字符串。

      #!/usr/bin/perl
      use strict;
      use warnings;
      
      my @ar=("asl","pwe","jsl","nxu","sl","baks","ak");
      foreach my $i (@ar){
        my $p = grep /$i/, @ar;
        if ( $p == 1 ){
          print "$i" , "\n";
        }
      } 
      

      【讨论】:

        【解决方案6】:

        我遇到了相反的问题:从列表中删除其他字符串的子字符串。这是我不太优雅的解决方案。

        sub remove_substrings_from_list {
            my @list = @_;
            my @vals_without_superstrings;
        
            my %hash_of_others;
            for ( 0 .. $#list ) {
                my $a = shift @list;
                $hash_of_others{$a} = [ @list ];
                push @list, $a;
            }
            foreach my $k ( keys %hash_of_others ) {
                push @vals_without_superstrings, $k unless grep { index( $_, $k ) != -1 } @{ $hash_of_others{$k} };
            }
            return @vals_without_superstrings;
        }
        

        【讨论】:

          猜你喜欢
          • 2015-06-23
          • 2015-05-16
          • 2020-08-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-09-24
          • 1970-01-01
          相关资源
          最近更新 更多