我有两个字符串数组,我想比较相等:
my @array1 = ("part1", "part2", "part3", "part4");
my @array2 = ("part1", "PART2", "part3", "part4");
是否有内置的比较数组的方法,就像标量一样? 我试过了:
if (@array1 == @array2) {...}
但它只是在标量上下文中评估每个数组,因此比较了每个数组的长度。
我可以使用自己的函数来完成它,但看起来这样的低级操作应该有一个内置的方法来完成它。有吗?
编辑:遗憾的是,我无法访问5.10+或可选组件。
答案 0 :(得分:56)
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
my @x = (1, 2, 3);
my @y = qw(1 2 3);
say "[@x] and [@y] match" if @x ~~ @y;
比较器在内部通过使用join将两个数组转换为字符串并使用
eq
比较字符串来比较两个数组。
我想这是一个有效的方法,但只要我们使用字符串比较,我宁愿使用类似的东西:
#!/usr/bin/perl
use strict;
use warnings;
use List::AllUtils qw( each_arrayref );
my @x = qw(1 2 3);
my @y = (1, 2, 3);
print "[@x] and [@y] match\n" if elementwise_eq( \(@x, @y) );
sub elementwise_eq {
my ($xref, $yref) = @_;
return unless @$xref == @$yref;
my $it = each_arrayref($xref, $yref);
while ( my ($x, $y) = $it->() ) {
return unless $x eq $y;
}
return 1;
}
如果您要比较的数组很大,加入它们将会做很多工作并消耗大量内存,而不是逐个比较每个元素。
更新:当然,应该测试这样的陈述。简单的基准:
#!/usr/bin/perl
use strict;
use warnings;
use Array::Compare;
use Benchmark qw( cmpthese );
use List::AllUtils qw( each_arrayref );
my @x = 1 .. 1_000;
my @y = map { "$_" } 1 .. 1_000;
my $comp = Array::Compare->new;
cmpthese -5, {
iterator => sub { my $r = elementwise_eq(\(@x, @y)) },
array_comp => sub { my $r = $comp->compare(\(@x, @y)) },
};
这是最糟糕的情况,其中elementwise_eq
必须遍历两个数组中的每个元素1_000次,并显示:
Rate iterator array_comp iterator 246/s -- -75% array_comp 1002/s 308% --
另一方面,最好的情况是:
my @x = map { rand } 1 .. 1_000;
my @y = map { rand } 1 .. 1_000;
Rate array_comp iterator array_comp 919/s -- -98% iterator 52600/s 5622% --然而,
iterator
表现下降得非常快:
my @x = 1 .. 20, map { rand } 1 .. 1_000;
my @y = 1 .. 20, map { rand } 1 .. 1_000;
Rate iterator array_comp iterator 10014/s -- -23% array_comp 13071/s 31% --
我没有看内存利用率。
答案 1 :(得分:22)
有Test::More的is_deeply()函数,它也会显示结构的不同之处,或Test::Deep的eq_deeply(),它不需要测试工具(并且只返回是真是假。
答案 2 :(得分:14)
不是内置的,但有Array::Compare。
这是Perl核心遗漏的操作之一,因为我认为这是教学的原因 - 也就是说,如果你想要这样做,可能会出现问题。我认为,最具说明性的例子是没有核心read_entire_file
功能;基本上,在核心中提供该功能会让人们认为这是一个好主意这样做,但相反,Perl的设计方式可以轻轻地推动您处理文件行 - 在 - 时间,这通常效率更高,也是更好的主意,但是新手程序员很少习惯,他们需要一些鼓励来实现目标。
这同样适用于:通过比较两个数组,可能有更好的方法来确定您要完成的任务。不是必然,但可能。所以Perl正在推动你思考实现目标的其他方法。
答案 3 :(得分:9)
Perl 5.10为您提供智能匹配运算符。
use 5.010;
if( @array1 ~~ @array2 )
{
say "The arrays are the same";
}
否则,正如你所说的那样,你将自己推出自己的产品。
答案 4 :(得分:8)
只要您使用的是perl 5.10或更新版本,就可以使用smart match operator。
if (@array1 ~~ @array2) {...}
答案 5 :(得分:6)
更简单的解决方案更快:
#!/usr/bin/perl
use strict;
use warnings;
use Array::Compare;
use Benchmark qw( cmpthese );
use List::AllUtils qw( each_arrayref );
my @x = 1 .. 1_000;
my @y = map { "$_" } 1 .. 1_000;
my $comp = Array::Compare->new;
cmpthese -2, {
iterator => sub { my $r = elementwise_eq(\(@x, @y)) },
my_comp => sub { my $r = my_comp(\(@x, @y)) },
array_comp => sub { my $r = $comp->compare(\(@x, @y)) },
};
@x = 1 .. 20, map { rand } 1 .. 1_000;
@y = 1 .. 20, map { rand } 1 .. 1_000;
cmpthese -2, {
iterator => sub { my $r = elementwise_eq(\(@x, @y)) },
my_comp => sub { my $r = my_comp(\(@x, @y)) },
array_comp => sub { my $r = $comp->compare(\(@x, @y)) },
};
sub elementwise_eq {
my ($xref, $yref) = @_;
return unless @$xref == @$yref;
my $it = each_arrayref($xref, $yref);
while ( my ($x, $y) = $it->() ) {
return unless $x eq $y;
}
return 1;
}
sub my_comp {
my ($xref, $yref) = @_;
return unless @$xref == @$yref;
my $i;
for my $e (@$xref) {
return unless $e eq $yref->[$i++];
}
return 1;
}
导致perl 5, version 14, subversion 2 (v5.14.2) built for x86_64-linux-gnu-thread-multi
:
Rate iterator array_comp my_comp
iterator 1544/s -- -67% -80%
array_comp 4697/s 204% -- -41%
my_comp 7914/s 413% 68% --
Rate iterator array_comp my_comp
iterator 63846/s -- -1% -75%
array_comp 64246/s 1% -- -75%
my_comp 252629/s 296% 293% --
答案 6 :(得分:2)
这个问题已经变成了一个非常有用的资源。 ++用于基准和讨论。
正如其他人所指出的,智能匹配功能存在问题,并且正在逐步淘汰其目前的形式。有些替代品不太聪明" (因此避免了这些问题),这些问题很小,速度很快,并且没有太多非CORE依赖项。
通过查看@brian d foy的几个blog posts以及 p5p邮件存档,您可以找到关于~~
未来历史的一些非常好的讨论的链接/ strong>来自@rjbs的帖子from 2011和2012。
比较数组可以简单而有趣!
use v5.20;
use match::smart;
my @x = (1, 2, 3);
my @y = qw(4 5 6);
my @z = qw(4 5 6);
say \@x |M| \@y ? "[\@x] and [\@y] match": "no match";
say \@y |M| \@z ? "[\@y] and [\@z] match": "no match";
__END__
@y and @z match, @x and @y do not
...如果阵列很简单,特别有趣。但是数组可能是一个复杂的事情,有时您需要比较结果中的不同类型的信息。为此,Array::Compare可以更轻松地进行微调比较。
答案 7 :(得分:2)
为了检查两个数组的相等性,试试这个。 在给定的代码中,如果%eq_or_not具有任何值,则两个数组都不相等,否则它们是相等的。
my @array1 = ("part1", "part2", "part3", "part4");
my @array2 = ("part1", "PART2", "part3", "part4");
my %eq_or_not;
@eq_or_not{ @array1 } = undef;
delete @eq_or_not{ @array2 };
答案 8 :(得分:1)
如果套管是唯一的区别,你可以简单地使用:
if (lc "@array1" eq lc "@array2") {...}
"@array1"
返回与join ( " ", @array1 )
答案 9 :(得分:1)
如果订单和重复值无关紧要但只有值相等(即设置比较),则可以使用Set::Scalar
。
它会重载常见的运算符,例如==
或!=
。
my @array1 = ("part1", "part2", "part3", "part4");
my @array2 = ("part1", "PART2", "part3", "part4");
if ( Set::Scalar->new(@array1) == Set::Scalar->new(@array2) ) {...}
或者,还有Algorithm::Diff
和List::Compare
。
答案 10 :(得分:1)
Data::Cmp
是最近的另一个选择。 cmp_data()
函数的操作类似于cmp
运算符(有关cmp
的用法,请参见perlop
)。
示例:
use 5.10;
use Data::Cmp qw/cmp_data/;
my @array1 = ("part1", "part2", "part3", "part4");
my @array2 = ("part1", "PART2", "part3", "part4");
my @array3 = ("part1", "PART2", "part3", "part4");
# sample usage
say "1 & 2 are different" if cmp_data(\@array1, \@array2) ;
sat "2 & 3 are the same" unless cmp_data(\@array2, \@array3) ;
还可以比较哈希值和更复杂的嵌套数据结构(在合理范围内)。对于没有非核心依赖性的单个模块,Data::Cmp
相当“聪明” ;-) ... errm我的意思是“有用”。
答案 11 :(得分:1)
我的核心解决方案 List::Util::all
:
http {
upstream loadbalancer {
server app1:5000 weight=6;
server app2:5000 weight=4;
}
server {
location / {
proxy_pass http://loadbalancer/;
}
}
}
events {
}
作为子程序:
use List::Util qw(all);
if (@array1 == @array2 && all { $array1[$_] eq $array2[$_] } 0..$#array1) {
print "matched\n";
}
如果您想要自定义比较:
# call me like string_array_equals([@array1], [@array2])
sub string_array_equals {
my ($array1, $array2) = @_;
@$array1 == @$array2 and
all { $array1->[$_] eq $array2->[$_] } 0..$#$array1;
}
此时,# call me like array_equals { $a eq $b } [@array1], [@array2]
sub array_equals(&$$) {
my ($compare, $array1, $array2) = @_;
@$array1 == @$array2 and
all {
local $a = $array1->[$_];
local $b = $array2->[$_];
$compare->($a, $b);
} 0..$#$array1;
}
不会节省太多空间,您可以只执行 all
:
for
答案 12 :(得分:0)
可以在标量上下文中使用grep函数(http://perldoc.perl.org/functions/grep.html#grep-BLOCK-LIST)
(0 eq(grep {$ array1 [$ _] ne $ array2 [$ _]} 0 .. $#array1))if $#array1 eq $#array2;
HIH。
答案 13 :(得分:0)
if (join(",",sort @a) eq join(",",sort @b))
如果可以忽略性能问题,正如这里的线程中多次提到的
答案 14 :(得分:-2)
如果唯一的标准是"它们是否相同?",而不是更复杂的问题,"它们是否相同,如果它们不同,如何?&#34 ;有更快/更丑陋的方法来做到这一点。例如,将每个数组的整体粉碎成两个标量并进行比较。
例如
my @array1 = ("part1", "part2", "part3", "part4");
my @array2 = ("part1", "PART2", "part3", "part4");
my $smash1 = join("", @array1);
my $smash2 = join("", @array2);
if ($smash1 eq $smash2)
{
# equal
}
else
{
#unequal
}
是的,我可能只是让Larry Wall哭了。