Perl中不区分大小写的唯一数组元素

7

我正在使用由模块List::MoreUtils导出的uniq函数,在数组中查找唯一元素。然而,我希望以不区分大小写的方式查找唯一元素。我该怎么做?

我已经使用Data::Dumper转储了数组的输出:

#! /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个回答

11

使用小写字母,lcmap语句一起使用:

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, @_;
}

这是如何工作的说明:

@_ 包含子例程的参数,并被传递到一个 grep 语句中。通过代码块时返回 true 的任何元素都会被 grep 语句返回。代码块包括一些细节:

  • $seen{$_}++ 在第一次看到元素时返回 0。 值仍然增加为 1,但在返回后(与 ++$seen{$_} 相对应,它会先增加,然后返回)。
  • 通过否定增量的结果,我们获得了第一个键的真值,并对每个后续的键返回假值。 因此,列表被重复消除。
  • sub 中的最后一个语句 grep 将返回一个列表,该列表又由 sub 返回。
  • map lc, @_ 简单地将 lc 函数应用于 @_ 中的所有元素。

这是由List::MoreUtils模块导出的相同uniq函数吗? - Neon Flash
确实如此。虽然由于子程序非常简单且短小,您可以直接复制粘贴它,从而避免加载模块。 - TLP
谢谢。我会理解子程序,然后直接使用它 :) 你能稍微解释一下grep的语法吗?哈希表%seen将数组元素用作键并检查它们的出现次数。但是,我不确定这整个语法是如何工作的。 - Neon Flash
@NeonFlash在我的回答中加入了一个解释。我认为这是一个相当巧妙地编写的子程序。 - TLP
这个语法版本稍微更加灵活:my @uniq_no_case = uniq map {lc $_} @elements; - HoldOffHunger
显示剩余2条评论

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()$定义,使得当且仅当$f($a$) eq f($b$)$时,$a$等价于$b$。例如,如果我们想要说两个单词在长度相同的情况下是等价的,则$f()$将是$length()$。
现在你可能会看到我为什么以这种方式编写算法 - 分类器函数可能不会产生原始列表的值。对于$f=length$的情况,我们想要选择单词,但一个单词的$f$是一个数字。

在哈希访问中使用 lc 比其他解决方案更好,因为它保留了输入的(第一个匹配的)大小写。 - LeoNerd
@LeoNerd 你到底在说什么?在哈希内部使用 lc 和在外部使用 lc 没有任何区别。 - TLP
我的意思是,与其他答案中给出的map lc ...解决方案相反。这个更好,因为它以原始大小写返回值,而不是强制小写。 - LeoNerd
啊哈,我现在明白了。然而,这不是OP所要求的。此外,谁能说原始情况是可取的呢?通常,名称是ucfirst(lc)。 - TLP
我相信 uniq() 库比这个版本有更多的支持和效率。 - HoldOffHunger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接