【问题标题】:Looking for duplicates in arrays inside arrays (multi-dimensional array)在数组内的数组中查找重复项(多维数组)
【发布时间】:2017-04-01 07:17:46
【问题描述】:

我遇到了一些麻烦,想知道是否有人可以解决它。 我想做的是:

  1. 打开一堆包含 .txt 文件的数据
  2. 创建一个包含 @array[@filenames][@data] 的多维数组
  3. 查找哪些文件在数据方面相互重复

这里我将一个文件放入一个变量中,使用正则表达式获取我的数据并将其放入一个数组中:

    while (my $row = <$fh>) {
        unless ($. == 0) {
            {
            local $/; # enable slurp
            @datalist = <$fh> =~ /\s*\d*\/\s*\d*\|\s*(.*?)\|.*?(?:.*?\|){4}\s*(\S*)\|(\S*).*\|/g; #extract article numbers # $1 = article number, $2 = quantity, $3 = unit
            }
            push(@arrayofarrays,[@datalist]);
            push(@filenames,$file);
            last;
            }
        }
        $numr++;
}
open(my $feh,">","test.txt");
print {$feh} Dumper \@arrayofarrays;

Dumper 显示我的数据看起来不错(伪结果使其易于阅读和简短):

$VAR1 = [
          [
            'data type1',
            'data type2',
            'data type3',
            'data type1',
            'data type2',
            'data type3',
            ...
          ],
          [
            'data type1',
            'data type2',
            'data type3',
            ...
          ],
        ...
     ];

所以我想知道是否有人知道一种简单的方法来检查数据集之间的重复项?我知道我可以使用

打印单个数据集

我所尝试的可能会更好地了解我需要做什么:

my $i = 0;
my $j = 0;
while ( $i <= scalar @arrayofarrays) {
    $j = 0;
    while ( $j <= scalar @arrayofarrays) {
        if (@{$arrayofarrays[$i]} eq @{$arrayofarrays[$j]}) {
            print "\n'$filenames[$i]' is duplicate to '$filenames[$j]'.";
            } $j++;
        } $i++;
    }

【问题讨论】:

  • 也许您可以edit your question 向我们展示您期望的输出。您的示例代码相当混乱。您正在比较每个二级数组中的元素数量,而不是任何元素。您正在使用字符串比较 (eq) 而不是数字比较 (==) 来比较这些数字。
  • 如果您想检查哪些文件是相同的,那么请忘记将它们全部读入内存。只需使用Digest::MD5 为它们中的每一个创建一个校验和并比较结果。

标签: arrays perl multidimensional-array


【解决方案1】:

我将创建一个数组散列,而不是数组数组,通过将子数组展平为字符串来从子数组的数据中生成键,可选地将它们转换为校验和(这适用于多维子数组)。您可能想阅读有关 PerlMonks 的讨论:

http://www.perlmonks.org/?node_id=1121378

给定一个已经存在的数组的抽象示例,子数组中有重复的数据(你可以测试它here on ideone.com):

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my @array = (
    [1,'John','ABXC12132328'],
    [0,'John','ABXC12132322'],
    [0,'John','ABXC12132322'],
    [0,'John','ABXC12132322'],
    [0,'John','ABXC12132322'],
    [0,'John','ABXC12132322'],
    [0,'John','ABXC12132322'],
    [0,'John','ABXC12132322'],
    [0,'John','ABXC12132322'],
    [0,'John','ABXC12132322'],
    [0,'John','ABXC12132322'],
    [0,'John','ABXC12132322'],
    [0,'John','ABXC12132322'],
    [0,'John','ABXC12132322'],
    [0,'John','ABXC12132322']
);
my %uniq_helper = ();
my @uniq_data = grep { !$uniq_helper{"@$_"}++ } @array;
print Dumper(\%uniq_helper) . "\n";
print Dumper(\@uniq_data) . "\n";

对于您的情况,它可能如下所示:

my %datalist;
while (my $row = <$fh>) {
    unless ($. == 0) {
        {
            local $/; # enable slurp
            @data = <$fh> =~ /\s*\d*\/\s*\d*\|\s*(.*?)\|.*?(?:.*?\|){4}\s*(\S*)\|(\S*).*\|/g; #extract article numbers # $1 = article number, $2 = quantity, $3 = unit
        }
        $datalist{"@data"} = \@data;
        push(@filenames,$file);
        last;
    }
}
$numr++;

【讨论】:

    【解决方案2】:

    当您创建 @dataList 时,为其创建一个密钥并在执行推送之前检查该密钥,例如:

    my %checkHash=undef;
    my $key=arrayKey(\@datalist);
    if (!$checkHash{$key}) {
        push(@arrayofarrays,[@datalist]);
        push(@filenames,$file);
        $checkHash{$key}=1;
        last;
    }
    
    sub arrayKey($) {
        my $arrayRef = shift;
        my $output=undef;
        for (@$arrayRef) {
            if (ref($_) eq 'ARRAY') {
                $output.="[";
                $output.=arrayKey($_);
                $output.="]";
            }
            else {
                $output.="$_,";
            }
        }
        return $output;
    }
    

    【讨论】:

    • 如果arrayKey 的唯一参数必须是数组引用,那么\@ 肯定是比$ 更好的原型。然后,您可以将子例程称为arrayKey(@datalist),一切仍然有效。请注意,像这里的大多数人一样,我认为原型比它们的价值要麻烦得多,我永远不会在针对初学者的示例中使用它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-26
    • 1970-01-01
    • 1970-01-01
    • 2011-10-09
    相关资源
    最近更新 更多