【问题标题】:How can I remove duplicates and sorting at the same time in Perl?如何在 Perl 中同时删除重复项和排序?
【发布时间】:2011-04-09 22:46:36
【问题描述】:

我有一个这样的数组

@uniqarr = qw(error 0 goodrecordno:6123, error 0 goodrecordno:6143, error 1 goodrecordno:10245, error 1 goodrecordno:10678, error 1 goodrecordno:10698, error 2 goodrecordno:16245, error 2 goodrecordno:16123);

我想要 o/p 为

error 0 goodrecordno:6123
error 1 goodrecordno:10245 
error 2 goodrecordno:16123

即每个错误都有相应的最低记录号。 任何人都可以在不使用 cpan 模块的情况下帮助我

提前致谢。

【问题讨论】:

  • 嗯?发布时请记住,Stack Overflow 旨在替代支付专家网站。使用神秘的速记来陈述您的问题不太可能在未来帮助任何人。该数组将被称为@uniqarr,除非您想要一个名为'goodrecord:6123,' 的键(with 键中的逗号),否则您不应将逗号放在qw() 列表中。什么是“o/p”? 输出?!您可以通过输入 4 个额外字符来避免很多混乱。
  • “不使用 CPAN 模块”?为什么?
  • 对不起老板...!我试图学习在没有 cpan 模块的情况下编写每个程序。所以我只想要没有它们 bcoz(因为)它们可能很简单使用 cpan 模块。我想从基础学习核心逻辑。对不起接下来的 o/p以后我会清楚地写下一切。感谢您的意见和建议。

标签: perl sorting duplicates


【解决方案1】:

这是基本的最小-最大问题,您会在 Perl 入门书籍中找到。您遍历所有元素并记住哪个元素是最低的。这比排序要好得多,排序是为您将所有元素按顺序排列而设计的,这不是您所追求的。

use strict;
use warnings;

# I'll assume those commas were a mistake. You don't need to separate
# items with commas in a quotewords list
# If I'm wrong, the process is the same although the data massaging
# will be a little different
my @elements = qw(
    error 0 goodrecordno:6123
    error 0 goodrecordno:6143
    error 1 goodrecordno:10245 
    error 1 goodrecordno:10678 
    error 1 goodrecordno:10698 
    error 2 goodrecordno:16245 
    error 2 goodrecordno:16123
    );

my %lowest;
while( my( $error, $number, $goodrecno ) = splice @elements, 0, 3, () )
    {
    my( $recno ) = $goodrecno =~ /(\d+)/;

    # This hash remembers the lowest $recno. If you find another
    # a lower number, you replace the previous value.
    $lowest{$number} = $recno if( 
        ! exists $lowest{$number} 
            ||
        $recno < $lowest{$number}
        );
    }

创建具有最低元素的哈希后,您只需将其打印出来:

foreach my $number ( sort { $a <=> $b } keys %lowest ) {
    print "error $number goodrecordno:$lowest{$number}\n";
    };

这将为您提供您正在寻找的输出:

error 0 goodrecordno:6123
error 1 goodrecordno:10245
error 2 goodrecordno:16123

这是此类问题的基本模板。第 1 步:扫描数据以记住您想要的内容,使用哈希来键入这些数据。第二步:输出哈希的内容。

【讨论】:

    【解决方案2】:

    要去除重复,最好的方法是使用List::MoreUtilsuniq,:

    use List::MoreUtils 'uniq';
    my @unique_list = uniq @list;
    

    或没有 CPAN(尽管这很少需要):

    my %values;
    @values{@list} = ();
    my @unique_list = keys %values;
    

    您可以使用内置函数 sort 对任何列表进行排序 -- 请参阅 perldoc -f sortperldoc -q 'How do I sort an array'


    顺便说一句,您引用的数据与您描述的行为不符。如果将数组声明为

    @uniqarr = qw(error 0 goodrecordno:6123, error 0 goodrecordno:6143, error 1 goodrecordno:10245, error 1 goodrecordno:10678, error 1 goodrecordno:10698, error 2 goodrecordno:16245, error 2 goodrecordno:16123);
    

    ...那么它的内容将包含:

    (
      'error',
      '0',
      'goodrecordno:6123,',
      'error',
      '0',
      'goodrecordno:6143,',
      'error',
      '1',
      'goodrecordno:10245,',
      'error',
      '1',
      'goodrecordno:10678,',
      'error',
      '1',
      'goodrecordno:10698,',
      'error',
      '2',
      'goodrecordno:16245,',
      'error',
      '2',
      'goodrecordno:16123'
    );
    

    您需要做的是将数据读入哈希表,然后根据您的标准进行解析。我不能走得更远,因为根本不清楚你在找什么。请阅读 perldoc perldataperldoc perldsc 以了解有关 Perl 数据结构的更多信息。

    【讨论】:

    • 你只关心按键,@values{@list} = (); 速度更快,占用内存更少。
    • @Chas:不错;我没有意识到如果没有相同长度的 RHS 列表,哈希切片也可以工作。
    • 您不想排序。这个问题的工作量太大了。我看不出这个答案是如何真正解决问题的。独特的元素在这里没有任何帮助。
    • @brian d foy 问题是“同时删除重复项和排序”。您没有看到如何使其独一无二并对结果进行排序解决了这个问题?
    • 我看到这是他在标题中所说的,但不是他在问题中提出的。不了解基本知识的人通常会要求他们真正想要的东西之外的东西,因为他们专注于解决方案(XY 问题)。我在回答中解释了如何在既不排序也不唯一的情况下做到这一点。你必须考虑真正的问题,而不是字面的问题。但是,您可以提交您的解决方案来展示您需要如何对列表进行排序和唯一化以完成此操作。
    【解决方案3】:

    正如其他人已经指出的那样,您的第一个问题是qw() 不适合建立此数组。

    有多种正确的方法,我将在此处使用哈希数组,这是更详细的选项,将技术修改为您选择的任何结构都相当容易。

    
    @uniqarr = (
      { error => 0, goodrecordno => 6123, },
      { error => 0, goodrecordno => 6143, },
      { error => 1, goodrecordno => 10245, },
      { error => 1, goodrecordno => 10678, },
      { error => 1, goodrecordno => 10698, },
      { error => 2, goodrecordno => 16245, },
      { error => 2, goodrecordno => 16123, },
    );
    

    然后提取每个具有最低 goodrecordno 的错误实例,我们可以执行以下操作。

    首先我们从 List::Util 中导入 min。这个模块是核心 Perl,不需要 CPAN。

    然后重构输入@uniqarr。对于我们想要按错误值分组的内容要容易得多。所以 by_error 是数组的散列。哈希的键是错误值,数组包含所有的goodrecordno值。

    最后我们产生了想要的输出。遍历散列意味着我们正在迭代每个错误值,排序以提供正确的输出顺序。然后我们提取最小的goodrecordno值。这只是留下打印输出。

    
    use List::Util qw(min); # In core Perl, not CPAN
    
    # Restructure input
    my %by_error; # Hash with error as key, array of goodrecordno as value.
    foreach (@uniqarr) {
      push @{$by_error{$_->{error}}}, $_->{goodrecordno};
    }
    
    # Output as desired
    foreach my $error (sort keys %by_error) {
      my $min_no = min @{$by_error{$error}};
      print "error $error goodrecordno:$min_no\n";
    }
    

    【讨论】:

      猜你喜欢
      • 2011-02-09
      • 1970-01-01
      • 1970-01-01
      • 2022-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-28
      相关资源
      最近更新 更多