如何在Perl中同时删除重复项和排序?

时间:2010-09-08 20:14:18

标签: perl sorting duplicates

我有一个这样的数组

@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模块

提前致谢。

3 个答案:

答案 0 :(得分:3)

这是您在开始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步:输出哈希的内容。

答案 1 :(得分:1)

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

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

或没有CPAN(虽然这很少需要):

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

您可以使用内置函数排序对任何列表进行排序 - 请参阅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数据结构的更多信息。

答案 2 :(得分:0)

正如其他人已经指出你的第一个问题是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";
}
相关问题