I have an array @test
. What's the best way to check if each element of the array is the same string?
我有一个@test数组。检查数组中的每个元素是否是相同的字符串的最好方法是什么?
I know I can do it with a foreach
loop but is there a better way to do this? I checked out the map function but I'm not sure if that's what I need.
我知道我可以用foreach循环来做,但是有更好的方法吗?我检查了map函数,但我不确定这是否是我需要的。
6 个解决方案
#1
11
If the string is known, you can use grep
in scalar context:
如果字符串已知,您可以在标量上下文中使用grep:
if (@test == grep { $_ eq $string } @test) {
# all equal
}
Otherwise, use a hash:
否则,使用一个散列:
my %string = map { $_, 1 } @test;
if (keys %string == 1) {
# all equal
}
or a shorter version:
或更短的版本:
if (keys %{{ map {$_, 1} @test }} == 1) {
# all equal
}
NOTE: The undef
ined value behaves like the empty string (""
) when used as a string in Perl. Therefore, the checks will return true if the array contains only empty strings and undef
s.
注意:未定义的值在Perl中用作字符串时的行为与空字符串(“”)类似。因此,如果数组只包含空字符串和undefs,那么检查将返回true。
Here's a solution that takes this into account:
这里有一个考虑到这一点的解决方案:
my $is_equal = 0;
my $string = $test[0]; # the first element
for my $i (0..$#test) {
last unless defined $string == defined $test[$i];
last if defined $test[$i] && $test[$i] ne $string;
$is_equal = 1 if $i == $#test;
}
#2
10
Both methods in the accepted post give you the wrong answer if @test = (undef, '')
. That is, they declare an undefined value to be equal to the empty string.
在已接受的post中,如果@test = (undef,”),这两个方法都会给出错误的答案。也就是说,它们声明一个未定义的值等于空字符串。
That might be acceptable. In addition, using grep
goes through all elements of the array even if a mismatch is found early on and using the hash more than doubles the memory used by elements of array. Neither of these would be a problem if you have small arrays. And, grep
is likely to be fast enough for reasonable list sizes.
这可能是可以接受的。此外,使用grep可以遍历数组的所有元素,即使在早期发现了不匹配,并且使用哈希比数组元素使用的内存增加了一倍以上。如果有小数组,这两个都不是问题。而且,grep可能足够快以满足合理的列表大小。
However, here is an alternative that 1) returns false for (undef, '')
and (undef, 0)
, 2) does not increase the memory footprint of your program and 3) short-circuits as soon as a mismatch is found:
但是,这里有一种替代方法:1)返回false for (undef,”)和(undef, 0), 2)并不会增加程序的内存占用,3)一旦发现不匹配就会短路:
#!/usr/bin/perl
use strict; use warnings;
# Returns true for an empty array as there exist
# no elements of an empty set that are different
# than each other (see
# http://en.wikipedia.org/wiki/Vacuous_truth)
sub all_the_same {
my ($ref) = @_;
return 1 unless @$ref;
my $cmpv = \ $ref->[-1];
for my $i (0 .. $#$ref - 1) {
my $this = \ $ref->[$i];
return unless defined $$cmpv == defined $$this;
return if defined $$this
and ( $$cmpv ne $$this );
}
return 1;
}
However, using List::MoreUtils::first_index is likely to be faster:
但是,使用List::MoreUtils::first_index可能会更快:
use List::MoreUtils qw( first_index );
sub all_the_same {
my ($ref) = @_;
my $first = \ $ref->[0];
return -1 == first_index {
(defined $$first != defined)
or (defined and $_ ne $$first)
} @$ref;
}
#3
4
TIMTOWTDI, and I've been reading a lot of Mark Jason Dominus lately.
TIMTOWTDI,我最近读了很多Mark Jason Dominus的作品。
use strict;
use warnings;
sub all_the_same {
my $ref = shift;
return 1 unless @$ref;
my $cmp = $ref->[0];
my $equal = defined $cmp ?
sub { defined($_[0]) and $_[0] eq $cmp } :
sub { not defined $_[0] };
for my $v (@$ref){
return 0 unless $equal->($v);
}
return 1;
}
my @tests = (
[ qw(foo foo foo) ],
[ '', '', ''],
[ undef, undef, undef ],
[ qw(foo foo bar) ],
[ '', undef ],
[ undef, '' ]
);
for my $i (0 .. $#tests){
print "$i. ", all_the_same($tests[$i]) ? 'equal' : '', "\n";
}
#4
3
You can check how many times the element in the array (@test) is repeated by counting it in a hash (%seen). You can check how many keys ($size) are present in the hash (%seen). If more than 1 key is present, you know that the elements in the array are not identical.
您可以通过在散列中计数(%seen)来检查数组(@test)中的元素重复了多少次。您可以检查散列中有多少个键($size)(见%)。如果有超过一个键,那么您就知道数组中的元素并不相同。
sub all_the_same {
my @test = @_;
my %seen;
foreach my $item (@test){
$seen{$item}++
}
my $size = keys %seen;
if ($size == 1){
return 1;
}
else{
return 0;
}
}
#5
2
I use List::Util::first
for all similar purposes.
我使用List::Util:::首先用于所有类似的用途。
# try #0: $ok = !first { $_ ne $string } @test;
# try #1: $ok = !first { (defined $_ != defined $string) || !/\A\Q$string\E\z/ } @test;
# final solution
use List::Util 'first';
my $str = shift @test;
my $ok = !first { defined $$_ != defined $str || defined $str && $$_ ne $str } map \$_, @test;
I used map \$_, @test
here to avoid problems with values that evaluate to false.
我在这里使用map \$_ @test来避免计算值为false的问题。
Note. As cjm noted fairly, using map
defeats the advantage of first short-circuiting. So I tip my hat to Sinan with his first_index
solution.
请注意。正如cjm所指出的,使用map击败了第一次短路的优势。所以我向Sinan推荐他的first_index解决方案。
#6
2
I think, we can use List::MoreUtils qw(uniq)
我想,我们可以用List: MoreUtils qw(uniq)
my @uniq_array = uniq @array;
my $array_length = @uniq_array;
$array_length == 1 ? return 1 : return 0;
#1
11
If the string is known, you can use grep
in scalar context:
如果字符串已知,您可以在标量上下文中使用grep:
if (@test == grep { $_ eq $string } @test) {
# all equal
}
Otherwise, use a hash:
否则,使用一个散列:
my %string = map { $_, 1 } @test;
if (keys %string == 1) {
# all equal
}
or a shorter version:
或更短的版本:
if (keys %{{ map {$_, 1} @test }} == 1) {
# all equal
}
NOTE: The undef
ined value behaves like the empty string (""
) when used as a string in Perl. Therefore, the checks will return true if the array contains only empty strings and undef
s.
注意:未定义的值在Perl中用作字符串时的行为与空字符串(“”)类似。因此,如果数组只包含空字符串和undefs,那么检查将返回true。
Here's a solution that takes this into account:
这里有一个考虑到这一点的解决方案:
my $is_equal = 0;
my $string = $test[0]; # the first element
for my $i (0..$#test) {
last unless defined $string == defined $test[$i];
last if defined $test[$i] && $test[$i] ne $string;
$is_equal = 1 if $i == $#test;
}
#2
10
Both methods in the accepted post give you the wrong answer if @test = (undef, '')
. That is, they declare an undefined value to be equal to the empty string.
在已接受的post中,如果@test = (undef,”),这两个方法都会给出错误的答案。也就是说,它们声明一个未定义的值等于空字符串。
That might be acceptable. In addition, using grep
goes through all elements of the array even if a mismatch is found early on and using the hash more than doubles the memory used by elements of array. Neither of these would be a problem if you have small arrays. And, grep
is likely to be fast enough for reasonable list sizes.
这可能是可以接受的。此外,使用grep可以遍历数组的所有元素,即使在早期发现了不匹配,并且使用哈希比数组元素使用的内存增加了一倍以上。如果有小数组,这两个都不是问题。而且,grep可能足够快以满足合理的列表大小。
However, here is an alternative that 1) returns false for (undef, '')
and (undef, 0)
, 2) does not increase the memory footprint of your program and 3) short-circuits as soon as a mismatch is found:
但是,这里有一种替代方法:1)返回false for (undef,”)和(undef, 0), 2)并不会增加程序的内存占用,3)一旦发现不匹配就会短路:
#!/usr/bin/perl
use strict; use warnings;
# Returns true for an empty array as there exist
# no elements of an empty set that are different
# than each other (see
# http://en.wikipedia.org/wiki/Vacuous_truth)
sub all_the_same {
my ($ref) = @_;
return 1 unless @$ref;
my $cmpv = \ $ref->[-1];
for my $i (0 .. $#$ref - 1) {
my $this = \ $ref->[$i];
return unless defined $$cmpv == defined $$this;
return if defined $$this
and ( $$cmpv ne $$this );
}
return 1;
}
However, using List::MoreUtils::first_index is likely to be faster:
但是,使用List::MoreUtils::first_index可能会更快:
use List::MoreUtils qw( first_index );
sub all_the_same {
my ($ref) = @_;
my $first = \ $ref->[0];
return -1 == first_index {
(defined $$first != defined)
or (defined and $_ ne $$first)
} @$ref;
}
#3
4
TIMTOWTDI, and I've been reading a lot of Mark Jason Dominus lately.
TIMTOWTDI,我最近读了很多Mark Jason Dominus的作品。
use strict;
use warnings;
sub all_the_same {
my $ref = shift;
return 1 unless @$ref;
my $cmp = $ref->[0];
my $equal = defined $cmp ?
sub { defined($_[0]) and $_[0] eq $cmp } :
sub { not defined $_[0] };
for my $v (@$ref){
return 0 unless $equal->($v);
}
return 1;
}
my @tests = (
[ qw(foo foo foo) ],
[ '', '', ''],
[ undef, undef, undef ],
[ qw(foo foo bar) ],
[ '', undef ],
[ undef, '' ]
);
for my $i (0 .. $#tests){
print "$i. ", all_the_same($tests[$i]) ? 'equal' : '', "\n";
}
#4
3
You can check how many times the element in the array (@test) is repeated by counting it in a hash (%seen). You can check how many keys ($size) are present in the hash (%seen). If more than 1 key is present, you know that the elements in the array are not identical.
您可以通过在散列中计数(%seen)来检查数组(@test)中的元素重复了多少次。您可以检查散列中有多少个键($size)(见%)。如果有超过一个键,那么您就知道数组中的元素并不相同。
sub all_the_same {
my @test = @_;
my %seen;
foreach my $item (@test){
$seen{$item}++
}
my $size = keys %seen;
if ($size == 1){
return 1;
}
else{
return 0;
}
}
#5
2
I use List::Util::first
for all similar purposes.
我使用List::Util:::首先用于所有类似的用途。
# try #0: $ok = !first { $_ ne $string } @test;
# try #1: $ok = !first { (defined $_ != defined $string) || !/\A\Q$string\E\z/ } @test;
# final solution
use List::Util 'first';
my $str = shift @test;
my $ok = !first { defined $$_ != defined $str || defined $str && $$_ ne $str } map \$_, @test;
I used map \$_, @test
here to avoid problems with values that evaluate to false.
我在这里使用map \$_ @test来避免计算值为false的问题。
Note. As cjm noted fairly, using map
defeats the advantage of first short-circuiting. So I tip my hat to Sinan with his first_index
solution.
请注意。正如cjm所指出的,使用map击败了第一次短路的优势。所以我向Sinan推荐他的first_index解决方案。
#6
2
I think, we can use List::MoreUtils qw(uniq)
我想,我们可以用List: MoreUtils qw(uniq)
my @uniq_array = uniq @array;
my $array_length = @uniq_array;
$array_length == 1 ? return 1 : return 0;