배열이 있다고 가정 해 봅시다. "배열에 X가 포함되어 있습니까?"라는 작업을 많이 할 것입니다. 체크 무늬. 이를 수행하는 효율적인 방법은 해당 배열을 해시로 바꾸는 것입니다. 여기서 키는 배열의 요소입니다. 그러면 다음과 같이 말할 수 있습니다.
if ($ hash {X}) {...}
이 배열에서 해시로 변환하는 쉬운 방법이 있습니까? 이상적으로는 익명 배열을 취하고 익명 해시를 반환 할 수있을만큼 다재다능해야합니다.
답변:
@hash{@array} = (1) x @array;
해시 조각, 해시의 값 목록이므로 앞에 list-y @가 표시됩니다.
에서 워드 프로세서 :
'%'대신 해시 슬라이스에 '@'를 사용하는 이유에 대해 혼란 스러우면 다음과 같이 생각하십시오. 대괄호 유형 (정사각형 또는 곱슬 곱슬 함)은 배열인지 해시인지 여부를 결정합니다. 반면에 배열 또는 해시의 선행 기호 ( '$'또는 '@')는 단수 값 (스칼라) 또는 복수 값 (목록)을 반환하는지 여부를 나타냅니다.
@hash{@keys} = undef;
여기서 해시를 참조하는 구문 @
은 해시 슬라이스입니다. 기본적으로 $hash{$keys[0]}
AND $hash{$keys[1]}
AND $hash{$keys[2]}
...는 =, lvalue의 왼쪽에있는 목록이고, 실제로 해시로 들어가 모든 명명 된 키에 대한 값을 설정하는 해당 목록에 할당합니다. 이 경우에는 하나의 값만 지정 했으므로 해당 값은에 들어가고 $hash{$keys[0]}
다른 해시 항목은 모두 정의되지 않은 값으로 자동 활성화 (활성화)됩니다. [여기에서 내 원래 제안은 식 = 1로 설정되었는데, 하나의 키를 1로 설정하고 다른 키를 undef
. 일관성을 위해 변경했지만 아래에서 볼 수 있듯이 정확한 값은 중요하지 않습니다.]
=의 왼쪽에있는 표현식 인 lvalue가 해시로 만들어진 목록이라는 것을 알게되면, 우리가 그것을 사용하는 이유가 이해되기 시작할 것입니다 @
. [Perl 6에서 변경 될 것이라고 생각합니다.]
여기서 아이디어는 해시를 세트로 사용한다는 것입니다. 중요한 것은 내가 부여하는 가치가 아닙니다. 키의 존재 일뿐입니다. 그래서 당신이 원하는 것은 다음과 같은 것이 아닙니다.
if ($hash{$key} == 1) # then key is in the hash
대신 :
if (exists $hash{$key}) # then key is in the set
실제로 exists
해시의 값을 사용하는 것보다 검사를 실행하는 것이 더 효율적입니다 .하지만 여기에서 중요한 것은 해시의 키만으로 집합을 표현한다는 개념입니다. 또한 누군가는 undef
여기에서 값 을 사용 하면 값을 할당하는 것보다 저장 공간을 덜 소비하게 된다고 지적했습니다 . (또한 값이 중요하지 않으므로 내 솔루션은 해시의 첫 번째 요소에만 값을 할당하고 다른 요소는 남겨두고 혼란을 덜 발생시킵니다. undef
다른 솔루션은 수레 바퀴를 돌려 값의 배열을 구축합니다. 해시; 완전히 낭비되는 노력).
= ()
, 아니 = undef
, 첫 번째 이후의 모든 값이 아닌 모든 값에 대해 암시 적으로 undef를 사용하는 일관성을 위해. (이 주석에서 설명했듯이를보고 undef
1로 변경하고 모든 해시 값에 영향을 미칠 수 있다고 생각 하기가 너무 쉽습니다 .)
타이핑 if ( exists $hash{ key } )
이 당신에게 너무 많은 일이 아니라면 (관심의 문제가 실제로 그 가치의 진실성보다는 키의 존재이기 때문에 사용하는 것을 선호합니다), 짧고 달콤한 것을 사용할 수 있습니다.
@hash{@key} = ();
여기에는 "배열에 X가 포함되어 있습니까?"를 수행하는 가장 효율적인 방법이라는 전제가 있습니다. 검사는 배열을 해시로 변환하는 것입니다. 효율성은 부족한 자원, 종종 시간, 때로는 공간, 때로는 프로그래머의 노력에 달려 있습니다. 목록과 목록의 해시를 동시에 유지하여 소비되는 메모리를 적어도 두 배로 늘리고 있습니다. 또한 테스트, 문서화 등에 필요한 더 많은 원본 코드를 작성하고 있습니다.
대안보기 목록 :: MoreUtils 모듈에서, 특히 기능으로 any()
, none()
, true()
와 false()
. 그들은 모두 조건 및 인수로 목록 유사으로 블록을 map()
하고 grep()
:
print "At least one value undefined" if any { !defined($_) } @list;
빠른 테스트를 실행하여 / usr / share / dict / words의 절반을 배열 (25000 단어)에로드 한 다음 두 배열을 사용하여 배열의 전체 사전 (5000 번째 단어마다)에서 선택한 11 단어를 찾습니다. -to-hash 메소드와 any()
List :: MoreUtils 의 기능.
소스에서 빌드 된 Perl 5.8.8에서 array-to-hash 방법은 방법보다 거의 1100 배 더 빠르게 실행됩니다 any()
(Ubuntu 6.06의 패키지 Perl 5.8.7에서 1300 배 더 빠름).
그러나 이것이 전체 이야기는 아닙니다. 배열에서 해시로 변환하는 데 약 0.04 초가 소요되며,이 경우 배열에서 해시로의 시간 효율성이 방법보다 1.5x-2 배 더 빠릅니다 any()
. 여전히 좋지만 별 만큼은 아닙니다.
내 직감은 array-to-hash 방법이 any()
대부분의 경우 에 이길 것이라는 것입니다. O 각 방법의 알고리즘 분석 등) 필요에 따라 List :: MoreUtils가 더 나은 솔루션이 될 수 있습니다. 확실히 더 유연하고 코딩이 덜 필요합니다. 기억하세요, 조기 최적화는 죄입니다 ... :)
List::MoreUtils
사용 사례에 따라 적절한 방법 일 수도 있고 아닐 수도 있습니다. 유스 케이스에는 많은 조회가있을 수 있습니다. 다른 사람들은 그렇지 않을 수도 있습니다. 요점은 배열에서 해시로 변환하고 구성원을 결정 List::MoreUtils
하는 근본적인 문제를 해결한다는 것 입니다. 여러 접근 방식을 알면 특정 사용 사례에 가장 적합한 방법을 선택할 수 있습니다.
Perl 5.10에는 마술에 가까운 ~~ 연산자가 있습니다.
sub invite_in {
my $vampires = [ qw(Angel Darla Spike Drusilla) ];
return ($_[0] ~~ $vampires) ? 0 : 1 ;
}
여기를 참조하십시오 : http://dev.perl.org/perl5/news/2007/perl-5.10.0.html
또한 가치가 완전성에 대한 지적,이 같은 길이의 배열이 작업을 수행하는 내 일반적인 방법 @keys
과 @vals
당신이 선호하는 해시이었다 ...
my %hash = map { $keys[$_] => $vals[$_] } (0..@keys-1);
@keys-1
입니다 $#keys
.
Raldi의 솔루션은 다음과 같이 강화할 수 있습니다 (원본의 '=>'는 필요하지 않음).
my %hash = map { $_,1 } @array;
이 기술은 텍스트 목록을 해시로 변환하는 데 사용할 수도 있습니다.
my %hash = map { $_,1 } split(",",$line)
또한 다음과 같은 값이있는 경우 : "foo = 1, bar = 2, baz = 3"다음을 수행 할 수 있습니다.
my %hash = map { split("=",$_) } split(",",$line);
[포함하도록 수정]
제공되는 또 다른 솔루션 (두 줄 사용)은 다음과 같습니다.
my %hash;
#The values in %hash can only be accessed by doing exists($hash{$key})
#The assignment only works with '= undef;' and will not work properly with '= 1;'
#if you do '= 1;' only the hash key of $array[0] will be set to 1;
@hash{@array} = undef;
Perl6 :: Junction을 사용할 수도 있습니다 .
use Perl6::Junction qw'any';
my @arr = ( 1, 2, 3 );
if( any(@arr) == 1 ){ ... }
집합 이론 연산을 많이하는 경우 Set :: Scalar 또는 유사한 모듈을 사용할 수도 있습니다 . 그런 다음 $s = Set::Scalar->new( @array )
세트를 빌드하고 다음 을 사용하여 쿼리 할 수 있습니다 $s->contains($m)
..
네임 스페이스를 오염시키지 않으려면 코드를 서브 루틴에 배치 할 수 있습니다.
my $hash_ref =
sub{
my %hash;
@hash{ @{[ qw'one two three' ]} } = undef;
return \%hash;
}->();
또는 더 나은 방법 :
sub keylist(@){
my %hash;
@hash{@_} = undef;
return \%hash;
}
my $hash_ref = keylist qw'one two three';
# or
my @key_list = qw'one two three';
my $hash_ref = keylist @key_list;
정말로 배열 참조를 전달하고 싶다면 :
sub keylist(\@){
my %hash;
@hash{ @{$_[0]} } = undef if @_;
return \%hash;
}
my @key_list = qw'one two three';
my $hash_ref = keylist @key_list;
%hash = map{ $_, undef } @keylist
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my @a = qw(5 8 2 5 4 8 9);
my @b = qw(7 6 5 4 3 2 1);
my $h = {};
@{$h}{@a} = @b;
print Dumper($h);
제공합니다 (반복 된 키는 배열의 가장 큰 위치에서 값을 얻습니다. 즉, 6이 아닌 8-> 2)
$VAR1 = {
'8' => '2',
'4' => '3',
'9' => '1',
'2' => '5',
'5' => '4'
};
정렬 된 연관 배열을 구현 하는 Tie :: IxHash 를 확인할 수도 있습니다 . 이를 통해 데이터 사본 하나에 대해 두 가지 유형의 조회 (해시 및 인덱스)를 모두 수행 할 수 있습니다.