Perl 如何从一个非';是否已在另一个数组中?

Perl 如何从一个非';是否已在另一个数组中?,perl,arrays,Perl,Arrays,鉴于: 在Perl中,在mylist2中插入所有在mylist1中但尚未在mylist2中的元素(ABCDE)的最快方法是什么 或者: my %k; map { $k{$_} = 1 } @mylist1; map { $k{$_} = 1 } @mylist2; @mylist2 = keys %k; 事实上,这些可能是错误的,因为它们没有考虑原始列表中是否存在重复项 在你的问题中,你没有说列表应该表示集合(不能包含重复项)还是仅仅表示普通列表。您实际上想要@mylist2=@mylist1

鉴于:

在Perl中,在mylist2中插入所有在mylist1中但尚未在mylist2中的元素(ABCDE)的最快方法是什么

或者:

my %k;
map { $k{$_} = 1 } @mylist1;
map { $k{$_} = 1 } @mylist2;
@mylist2 = keys %k;
事实上,这些可能是错误的,因为它们没有考虑原始列表中是否存在重复项

在你的问题中,你没有说列表应该表示集合(不能包含重复项)还是仅仅表示普通列表。您实际上想要
@mylist2=@mylist1 U@mylist2
表明您将它们视为集合

编辑:将增量更改为赋值-保存散列值的读数。[从2008年11月27日起的原始答案改为“自问题开始”;从2008年11月29日起,该分析是新的。]

最快-不确定。这是可行的,尽管它并不漂亮:

my %k;
map { $k{$_} = 1 } @mylist2;
push(@mylist2, grep { !exists $k{$_} } @mylist1);
这避免了将数组转换为散列-但是对于大型数组,sub中的
value\u可能会很慢

因为问题是“什么是最快的方法”,我做了一些基准测试。令我毫不惊讶的是,我的方法是最慢的。让我有点惊讶的是,最快的方法不是来自List::MoreUtils。下面是测试代码和结果-使用我原来建议的修改版本

#!/bin/perl -w
use strict;

my @mylist1;
push(@mylist1,"A");
push(@mylist1,"B");
push(@mylist1,"C");

my @mylist2;
push(@mylist2,"A");
push(@mylist2,"D");
push(@mylist2,"E");

sub value_in
{
    my($value, @array) = @_;
    foreach my $element (@array)
    {
        return 1 if $value eq $element;
    }
    return 0;
}

@mylist2 = (@mylist2, grep { ! value_in($_, @mylist2) } @mylist1);

print sort @mylist2, "\n";
这是在运行Solaris 10的老式Sun E450上为32位SPARC编译的Perl 5.10.0,具有多重性

我相信测试设置是公平的;它们都将答案生成一个新的数组,与mylist1和mylist2分开(这样mylist1和mylist2可以在下一次测试中重用)。指定为HV1(散列值1)的答案在@mylist5赋值后开始计时,我认为这是正确的。然而,当我在作业前开始计时时,它仍然是最快的:

#!/bin/perl -w
use strict;
use List::MoreUtils  qw(uniq);
use Benchmark::Timer;

my @mylist1;
push(@mylist1,"A");
push(@mylist1,"B");
push(@mylist1,"C");

my @mylist2;
push(@mylist2,"A");
push(@mylist2,"D");
push(@mylist2,"E");

sub value_in
{
    my($value) = shift @_;
    return grep { $value eq $_ } @_;
}

my @mylist3;
my @mylist4;
my @mylist5;
my @mylist6;

my $t = Benchmark::Timer->new(skip=>1);
my $iterations = 10000;

for my $i (1..$iterations)
{
    $t->start('JLv2');
    @mylist3 = (@mylist2, grep { ! value_in($_, @mylist2) } @mylist1);
    $t->stop('JLv2');
}
print $t->report('JLv2');

for my $i (1..$iterations)
{
    $t->start('LMU');
    @mylist4 = uniq( @mylist1, @mylist2 );
    $t->stop('LMU');
}
print $t->report('LMU');

for my $i (1..$iterations)
{
    @mylist5 = @mylist2;
    $t->start('HV1');
    my %k;
    map { $k{$_} = 1 } @mylist5;
    push(@mylist5, grep { !exists $k{$_} } @mylist1);
    $t->stop('HV1');
}
print $t->report('HV1');

for my $i (1..$iterations)
{
    $t->start('HV2');
    my %k;
    map { $k{$_} = 1 } @mylist1;
    map { $k{$_} = 1 } @mylist2;
    @mylist6 = keys %k;
    $t->stop('HV2');
}
print $t->report('HV2');


print sort(@mylist3), "\n";
print sort(@mylist4), "\n";
print sort(@mylist5), "\n";
print sort(@mylist6), "\n";

Black JL: perl xxx.pl
9999 trials of JLv2 (1.298s total), 129us/trial
9999 trials of LMU (968.176ms total), 96us/trial
9999 trials of HV1 (516.799ms total), 51us/trial
9999 trials of HV2 (768.073ms total), 76us/trial
ABCDE
ABCDE
ABCDE
ABCDE
Black JL:
由于您的“(ABCDE)”注释,我假设您实际上是想将mylist2中不在mylist1中的元素推到mylist1上。如果这个假设是不正确的,你需要说明你希望事情以什么样的顺序结束

首先,将mylist1中的元素存储在哈希中,然后将mylist2中未在哈希中找到的所有元素推送到mylist1上

Black JL: perl xxx.pl
9999 trials of JLv2 (1.293s total), 129us/trial
9999 trials of LMU (938.504ms total), 93us/trial
9999 trials of HV1 (505.998ms total), 50us/trial
9999 trials of HV2 (756.722ms total), 75us/trial
ABCDE
ABCDE
ABCDE
ABCDE
9999 trials of HV1A (655.582ms total), 65us/trial
Black JL:
您可以使用模块的
uniq

my %in_mylist1;
@in_mylist1{@mylist1} = ();
push @mylist1, grep ! exists $in_mylist1{$_}, @mylist2;

学习识别和使用模块是学习perl非常重要的一部分。当然,但是你仍然需要知道基本原理。我希望更多的人使用List::MoreUtils,而不是一遍又一遍地编写相同的代码。如果不需要保持原始顺序,这是可以的。根据我的测量,第二个选项是最快的,并且比List::MoreUtils中的uniq方法更快。如果重复的话在mylist2中允许(我认为没有理由不允许),然后此解决方案将删除它们。
my %in_mylist1;
@in_mylist1{@mylist1} = ();
push @mylist1, grep ! exists $in_mylist1{$_}, @mylist2;
use List::MoreUtils qw(uniq);

my @mylist1;
push( @mylist1, "A" );
push( @mylist1, "B" );
push( @mylist1, "C" );

my @mylist2;
push( @mylist2, "A" );
push( @mylist2, "D" );
push( @mylist2, "E" );

@mylist2 = uniq( @mylist1, @mylist2 );

printf "%s\n", ( join ',', @mylist2 );    # A,B,C,D,E
my(%work);
@work{@mylist1, @mylist2} = undef;
@mylist2 = sort keys %work;