【问题标题】:Case Insensitive Unique Array Elements in PerlPerl 中不区分大小写的唯一数组元素
【发布时间】:2012-10-25 17:08:01
【问题描述】:

我正在使用模块导出的 uniq 函数 List::MoreUtils 来查找数组中的 uniq 元素。但是,我希望它以不区分大小写的方式查找 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个元素,其余的都应该过滤,因为它们是同一个词,只是大小写不同。

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

【问题讨论】:

    标签: perl uniq


    【解决方案1】:

    使用小写字母 lcmap 语句:

    my @uniq_no_case = uniq map lc, @elements;
    

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

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

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

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

    解释这是如何工作的:

    @_ 包含子程序的参数,它们被馈送到grep 语句。通过代码块时返回 true 的任何元素都由 grep 语句返回。代码块包含一些更精细的点:

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

    【讨论】:

    • 这和 List::MoreUtils 模块导出的 uniq 函数是一样的吗?
    • 确实如此。虽然由于 sub 非常简单和简短,您可以复制粘贴它,而无需自己加载模块。
    • 谢谢。我会理解子程序,然后直接使用它:) 你能解释一下grep语法吗?哈希 %seen 使用数组的元素作为键并检查它们的出现。但是,我不确定整个语法是如何工作的。
    • @NeonFlash 在我的回答中添加了解释。我认为这是一个相当巧妙的编写子。
    • @NeonFlash 如果这个答案让您满意地解决了您的问题,请不要忘记点击复选标记接受它。
    【解决方案2】:

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

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

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

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

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

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

    【讨论】:

    • 在哈希访问中使用lc 比给出的其他解决方案要好得多,因为它保留了输入中的(第一个匹配)大小写。
    • @LeoNerd 你到底在说什么?在哈希之前和内部使用 lc 没有区别。
    • 我的意思是,与其他答案中给出的 map lc ... 解决方案相反。这个更好,因为它返回原始大小写的值,而不是强制小写。
    • 啊哈,我现在明白了。但是,这不是 OP 所要求的。此外,谁能说原案是可取的?通常,名称是 ucfirst(lc)。
    • 相信uniq()库比这个版本有更多的支持和效率。
    猜你喜欢
    • 1970-01-01
    • 2012-01-31
    • 2013-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-15
    • 2020-04-14
    • 2016-02-17
    相关资源
    最近更新 更多