Perl에서 키가 주어진 배열에서 나온 해시를 어떻게 생성합니까?
배열이 있다고 가정 해 봅시다. "배열에 X가 포함되어 있습니까?"라는 작업을 많이 할 것입니다. 체크 무늬. 이를 수행하는 효율적인 방법은 해당 배열을 해시로 바꾸는 것입니다. 여기서 키는 배열의 요소입니다. 그러면 다음과 같이 말할 수 있습니다.
if ($ hash {X}) {...}
이 배열에서 해시로 변환하는 쉬운 방법이 있습니까? 이상적으로는 익명 배열을 취하고 익명 해시를 반환 할 수있을만큼 다재다능해야합니다.
%hash = map { $_ => 1 } @array;
"@hash {@array} = ..."솔루션만큼 짧지는 않지만 이러한 솔루션은 해시와 배열이 이미 다른 곳에 정의되어 있어야하지만이 솔루션은 익명 배열을 가져와 익명 해시를 반환 할 수 있습니다.
이것이하는 일은 배열의 각 요소를 "1"과 쌍으로 만드는 것입니다. 이 (key, 1, key, 1, key 1) 쌍 목록이 해시에 할당되면 홀수 번호가 해시 키가되고 짝수 번호가 각각의 값이됩니다.
@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
일으키며 다른 솔루션은 이동할 값의 배열을 구축하기 위해 수레 바퀴를 돌리고 있습니다. 해시; 완전히 낭비되는 노력).
타이핑 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()
. 여전히 좋지만 별 만큼은 아닙니다.
내 직감은 배열 대 해시 방법이 any()
대부분의 경우 이길 것이라는 것입니다.하지만 좀 더 확실한 메트릭 (많은 테스트 사례, 괜찮은 통계 분석, 아마도 큰-)이 있다면 훨씬 더 기분이 좋을 것입니다. O 각 방법에 대한 알고리즘 분석 등) 필요에 따라 List :: MoreUtils가 더 나은 솔루션이 될 수 있습니다. 확실히 더 유연하고 코딩이 덜 필요합니다. 기억하세요, 조기 최적화는 죄입니다 ... :)
나는 항상 생각했다
foreach my $item (@array) { $hash{$item} = 1 }
적어도 멋지고 읽기 쉽고 유지 관리가 가능했습니다.
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);
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 ){ ... }
If you do a lot of set theoretic operations - you can also use Set::Scalar or similar module. Then $s = Set::Scalar->new( @array )
will build the Set for you - and you can query it with: $s->contains($m)
.
You can place the code into a subroutine, if you don't want pollute your namespace.
my $hash_ref =
sub{
my %hash;
@hash{ @{[ qw'one two three' ]} } = undef;
return \%hash;
}->();
Or even better:
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;
If you really wanted to pass an array reference:
sub keylist(\@){
my %hash;
@hash{ @{$_[0]} } = undef if @_;
return \%hash;
}
my @key_list = qw'one two three';
my $hash_ref = keylist @key_list;
You might also want to check out Tie::IxHash, which implements ordered associative arrays. That would allow you to do both types of lookups (hash and index) on one copy of your data.
#!/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);
gives (note repeated keys get the value at the greatest position in the array - ie 8->2 and not 6)
$VAR1 = {
'8' => '2',
'4' => '3',
'9' => '1',
'2' => '5',
'5' => '4'
};
'developer tip' 카테고리의 다른 글
Linux에서 R에 사용할 수있는 IDE는 무엇입니까? (0) | 2020.10.13 |
---|---|
장고에서 현재 언어를 얻는 방법은 무엇입니까? (0) | 2020.10.13 |
DateTime. 날짜가 30 일 미만인지 확인하는 방법을 비교합니까? (0) | 2020.10.13 |
Angular 6 재질 매트 선택 변경 방법 제거 (0) | 2020.10.13 |
Ruby on Rails에서 호스트 이름 또는 IP 가져 오기 (0) | 2020.10.13 |