Perl中的Case不敏感唯一数组元素

时间:2012-10-25 17:08:01

标签: perl uniq

我使用模块导出的uniq函数,List :: MoreUtils来查找数组中的uniq元素。但是,我希望它以不区分大小写的方式查找uniq元素。我怎么能这样做?

我使用Data :: Dumper转储了Array的输出:

#! /usr/bin/perl

use strict;
use warnings;
use Data::Dumper qw(Dumper);
use List::MoreUtils qw(uniq);
use feature "say";

my @elements=<array is formed here>;

my @words=uniq @elements;

say Dumper \@words;

输出:

$VAR1 = [
          'John',
          'john',
          'JohN',
          'JOHN',
          'JoHn',
          'john john'
        ];

预期输出应该是:john,john john

只有2个元素,其余全部应该被过滤,因为它们是同一个单词,只有区别在于大小写。

如何删除忽略大小写的重复元素?

2 个答案:

答案 0 :(得分:9)

使用带有lc语句的小写map

my @uniq_no_case = uniq map lc, @elements;

List::MoreUtils' uniq区分大小写的原因是它依赖于散列的重复数据删除特征,这也是区分大小写的。 uniq的代码如下所示:

sub uniq {
    my %seen = ();
    grep { not $seen{$_}++ } @_;
}

如果您想直接在自己的代码中使用此子代码,可以在其中加入lc

sub uniq_no_case {
    my %seen = ();
    grep { not $seen{$_}++ } map lc, @_;
}

解释这是如何工作的:

@_包含子例程的args,它们被送入grep语句。通过代码块时返回true的任何元素都由grep语句返回。代码块由几个更精细的点组成:

  • $seen{$_}++在第一次看到元素时返回0。该值仍然会增加到1,但在返回之后(与首先出现的++$seen{$_}相反,然后返回)。
  • 通过否定递增的结果,我们对第一个键得到true,对于后面的每个键得到false。因此,该列表被重复使用。
  • grep作为sub中的最后一个语句将返回一个列表,该列表又由子返回。
  • map lc, @_只是将lc函数应用于@_中的所有元素。

答案 1 :(得分:6)

使用哈希来跟踪您已经看过的单词,但也可以将它们标准化为大写/小写:

my %seen;
my @unique;
for my $w (@words) {
  next if $seen{lc($w)}++;
  push(@unique, $w);
}
# @unique has the unique words

请注意,这将保留原始单词的大小写。

更新:如评论中所述,目前尚不清楚OP需要什么,但我用这种方式编写了解决方案,以说明在某种“等价关系”下从列表中选择唯一代表的一般技术。在这种情况下,当且仅当$a时,等价关系是单词$b等同于单词lc($a) eq lc($b)

大多数等价关系可以用这种方式表示,也就是说,关系是由分类器函数f()定义的,这样$a等同于$b当且仅当f($a) eq f($b) 1}}。例如,如果我们想要说两个单词长度相同,那么f()就是length()

所以现在您可能会看到为什么我以这种方式编写算法 - 分类器函数可能不会生成属于原始列表的值。在f = length的情况下,我们想要选择单词,但单词的f是一个数字。