6

我正在使用模块导出的 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 个元素,其余的都应该被过滤,因为它们是同一个词,只是大小写不同。

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

4

2 回答 2

10

使用小写,lc带有map语句:

my @uniq_no_case = uniq map lc, @elements;

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

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

如果你想在你自己的代码中直接使用这个 sub,你可以lc在其中合并:

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

解释这是如何工作的:

@_包含子例程的 args,并将它们提供给grep语句。通过代码块时返回 true 的任何元素都由 grep 语句返回。代码块包含一些更精细的点:

  • $seen{$_}++第一次看到元素时返回 0。该值仍会增加到 1,但在返回之后(而不是先++$seen{$_}inc,然后返回)。
  • 通过否定递增的结果,我们得到第一个键的真值,而后面​​的每个键都为假。因此,该列表被重复数据删除。
  • grep因为 sub 中的最后一条语句将返回一个列表,该列表又由 sub 返回。
  • map lc, @_只需将该lc函数应用于@_.
于 2012-10-25T17:09:50.720 回答
6

使用散列来跟踪您已经看到的单词,但也将它们标准化为大写/小写:

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

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

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

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

所以现在你可能明白我为什么用这种方式编写算法了——分类器函数可能不会产生原始列表中的值。在 的情况下f = length,我们要选择单词,但是f单词的 是一个数字。

于 2012-10-25T17:11:36.363 回答