Perl에서는 주어진 배열에서 키를 가져오는 해시를 어떻게 생성합니까?

StackOverflow https://stackoverflow.com/questions/95820

  •  01-07-2019
  •  | 
  •  

문제

배열이 있다고 가정 해 봅시다. 그리고 나는 "배열에 x가 포함되어 있습니까?"를 많이 할 것임을 알고 있습니다. 체크 무늬.이를 수행하는 효율적인 방법은 해당 배열을 해시로 바꾸는 것입니다. 여기서 키는 배열의 요소입니다. 그런 다음 다음과 같이 말할 수 있습니다.

if($hash{X}) { ... }

배열에서 해시로 변환하는 쉬운 방법이 있습니까?이상적으로는 익명 배열을 사용하고 익명 해시를 반환할 수 있을 만큼 다재다능해야 합니다.

도움이 되었습니까?

해결책

%hash = map { $_ => 1 } @array;

"@hash{@array} = ..." 솔루션만큼 짧지는 않지만 이러한 솔루션에서는 해시와 배열이 이미 다른 곳에 정의되어 있어야 하는 반면 이 솔루션은 익명 배열을 가져와 익명 해시를 반환할 수 있습니다.

이것이 하는 일은 배열의 각 요소를 가져와 "1"과 쌍을 이루는 것입니다.이 (키, 1, 키, 1, 키 1) 쌍 목록이 해시에 할당되면 홀수 번호가 해시의 키가 되고 짝수 번호가 해당 값이 됩니다.

다른 팁

 @hash{@array} = (1) x @array;

이는 해시 값 목록인 해시 슬라이스이므로 앞에 목록-y @를 가져옵니다.

에서 문서:

왜 '%'대신 해시 슬라이스에 '@'를 사용하는 이유에 대해 혼란 스러우면 이렇게 생각하십시오.브래킷의 유형 (정사각형 또는 곱슬)은 배열이든 해시를 보는지 여부에 관계없이 적용됩니다.한편, 배열 또는 해시의 주요 기호 ( '$'또는 '@')는 단일 값 (스칼라) 또는 복수 값 (목록)을 되 찾는 지 여부를 나타냅니다.

@hash{@keys} = undef;

여기에서 해시를 참조하는 구문은 다음과 같습니다. @ 해시 슬라이스입니다.우리는 기본적으로 말하고 있습니다 $hash{$keys[0]} 그리고 $hash{$keys[1]} 그리고 $hash{$keys[2]} ...=의 왼쪽에 있는 목록인 lvalue를 해당 목록에 할당합니다. 이 목록은 실제로 해시로 들어가 명명된 모든 키에 대한 값을 설정합니다.이 경우에는 하나의 값만 지정했으므로 해당 값은 $hash{$keys[0]}, 기타 해시 항목은 모두 정의되지 않은 값으로 자동 활성화(활성화)됩니다.[여기서 나의 원래 제안은 표현식 = 1로 설정되었습니다. 그러면 해당 키 하나는 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가 포함되어 있습니까?"를하는 가장 효율적인 방법은 여기에 전제가 있습니다. 점검은 배열을 해시로 변환하는 것입니다.효율성은 부족한 자원, 즉 시간이 많을 때도 있지만 공간이 있을 때도 있고 프로그래머의 노력에 따라 달라집니다.목록과 목록의 해시를 동시에 유지하면 소비되는 메모리가 최소한 두 배로 늘어납니다.또한 테스트, 문서화 등에 필요한 보다 독창적인 코드를 작성하게 됩니다.

대안으로 List::MoreUtils 모듈, 특히 함수를 살펴보세요. any(), none(), true() 그리고 false().그들은 모두 조건부로 블록을 취하고 인수로 목록을 취합니다. map() 그리고 grep():

print "At least one value undefined" if any { !defined($_) } @list;

/usr/share/dict/words의 절반을 배열(25000단어)에 로드한 다음 두 배열을 모두 사용하여 배열의 전체 사전(5000번째 단어마다)에서 선택된 11개의 단어를 찾는 빠른 테스트를 실행했습니다. -해시 방법 및 any() List::MoreUtils의 함수입니다.

소스에서 빌드된 Perl 5.8.8에서 배열-해시 방법은 Perl 5.8.8보다 거의 1100배 빠르게 실행됩니다. any() 방법(Ubuntu 6.06의 Perl 5.8.7 패키지에서는 1300배 더 빠릅니다.)

그러나 이것이 전부는 아닙니다. 배열에서 해시로 변환하는 데 약 0.04초가 소요됩니다. 이 경우 배열에서 해시로 변환하는 방법의 시간 효율성이 이전보다 1.5x-2x 더 빨라집니다. any() 방법.여전히 좋지만 별만큼은 아닙니다.

내 직감은 배열-해시 방법이 이길 것이라는 것입니다 any() 대부분의 경우, 그러나 좀 더 견고한 측정항목(많은 테스트 사례, 적절한 통계 분석, 각 방법에 대한 일부 Big-O 알고리즘 분석 등)이 있으면 훨씬 더 기분이 좋을 것입니다. 필요에 따라 목록을 작성하세요. ::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

완전성을 위해 주목할 가치가 있는 것은 2개의 동일한 길이 배열을 사용하여 이 작업을 수행하는 일반적인 방법입니다. @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::정션.

use Perl6::Junction qw'any';

my @arr = ( 1, 2, 3 );

if( any(@arr) == 1 ){ ... }

집합 이론 연산을 많이 수행하는 경우 다음을 사용할 수도 있습니다. 세트::스칼라 또는 유사한 모듈.그 다음에 $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;

확인해 보시는 것도 좋을 것 같습니다 타이::IxHash, 순서가 지정된 연관 배열을 구현합니다.그러면 하나의 데이터 복사본에 대해 두 가지 유형의 조회(해시 및 인덱스)를 모두 수행할 수 있습니다.

#!/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'
        };
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top