BagHash — 변경 가능한 다중집합(가중치 컬렉션)
BagHash — 변경 가능한 다중집합(가중치 컬렉션)
Bag이 불변이라면 BagHash는 값의 가중치를 나중에 바꿀 수 있는 변경 가능한(mutable) 다중집합이에요. 순서 없이 요소마다 정수 가중치를 매겨 '그 요소가 몇 개인지'를 나타내요. 가변성이 필요 없다면 불변 버전인 Bag을 쓰는 걸 고려해보세요.
class BagHash does Baggy { }
본문
요소는 Str뿐 아니라 어떤 타입의 definite 객체도 될 수 있어요. 예를 들어 Sub을 BagHash에 저장하면, 그 이름과 같은 문자열이 아니라 실제 Sub를 저장해요. BagHash 안에서는 === 연산자로 같게 판정되는 항목들이 같은 요소로 취급되고, 그 수가 가중치가 돼요. 확장된 항목 리스트(순서 없이)를 얻으려면 kxxv 메서드를 쓰면 돼요.
my $breakfast = <spam eggs spam spam bacon spam>.BagHash;
say $breakfast.elems; # OUTPUT: «3»
say $breakfast.keys.sort; # OUTPUT: «bacon eggs spam»
say $breakfast.total; # OUTPUT: «6»
say $breakfast.kxxv.sort; # OUTPUT: «bacon eggs spam spam spam spam»
BagHash는 { } postcircumfix 연산자(또는 문자열 키용 <>)로 객체 해시처럼 다룰 수 있어요. 요소인 키에 대해 정수 가중치를 돌려주고, 요소가 아닌 키에는 0을 돌려줘요. 이 연산자들로 가중치를 수정할 수도 있어요(아래 BagHash 객체 갱신 참고).
my $breakfast = <spam eggs spam spam bacon spam>.BagHash;
say $breakfast<bacon>; # OUTPUT: «1»
say $breakfast<spam>; # OUTPUT: «4»
say $breakfast<sausage>; # OUTPUT: «0»
$breakfast<sausage> = 2;
$breakfast<bacon>--;
say $breakfast.kxxv.sort; # OUTPUT: «eggs sausage sausage spam spam spam spam»
BagHash 객체 만들기
BagHash.new로 BagHash를 만들 수 있어요. 타입과 무관하게 위치 인자들이 bag의 요소가 돼요.
my $n = BagHash.new: "a", "b", "c", "c";
say $n.raku; # OUTPUT: «("b"=>1,"a"=>1,"c"=>2).BagHash»
say $n.keys.raku; # OUTPUT: «("b", "a", "c").Seq»
say $n.values.raku; # OUTPUT: «(1, 1, 2).Seq»
또한 BagHash.new-from-pairs로 항목과 그 발생 횟수를 가진 BagHash를 만들 수 있어요.
my $n = BagHash.new-from-pairs: "a" => 0, "b" => 1, "c" => 2, "c" => 2;
say $n.raku; # OUTPUT: «("b"=>1,"c"=>4).BagHash»
say $n.keys.raku; # OUTPUT: «("b", "c").Seq»
say $n.values.raku; # OUTPUT: «(1, 4).Seq»
또는 기존 객체에 .BagHash 강제 변환(또는 함수형 BagHash())을 호출해 바꿀 수 있어요. 해시류 객체나 Pair 항목은 키만 요소가 되고 (누적된) 값이 가중치가 돼요.
my $m = ("a", "b", "c", "c").BagHash;
my $n = ("a" => 0, "b" => 1, "c" => 2, "c" => 2).BagHash;
say $m.raku; # OUTPUT: «("b"=>1,"a"=>1,"c"=>2).BagHash»
say $n.raku; # OUTPUT: «("b"=>1,"c"=>4).BagHash»
is 트레이트로 해시처럼 가장하는 BagHash도 만들 수 있어요.
my %bh is BagHash = <a b b c c c>;
say %bh<b>; # OUTPUT: «2»
say %bh<d>; # OUTPUT: «0»
6.d(2019.03 이후)부터는 BagHash에 허용할 값 타입을 지정할 수도 있어요. .new 호출 시 지정하거나:
# only allow strings
my $n = BagHash[Str].new: <a b b c c c>;
가장 문법으로 지정할 수 있어요:
# only allow strings
my %bh is BagHash[Str] = <a b b c c c>;
say %bh<b>; # OUTPUT: «2»
say %bh<d>; # OUTPUT: «0»
# only allow whole numbers
my %bh is BagHash[Int] = <a b b c c c>;
# Type check failed in binding; expected Int but got Str ("a")
BagHash 객체 갱신
BagHash를 만든 뒤 값을 두 가지 방법으로 갱신할 수 있어요. 첫째는 add와 remove 메서드를 쓰는 거예요:
my $n = BagHash.new: "a", "b", "c", "c";
say $n.raku; # OUTPUT: «("b"=>1,"a"=>1,"c"=>2).BagHash»
$n.add('c');
say $n.raku; # OUTPUT: «("b"=>1,"c"=>3,"a"=>1).BagHash»
$n.remove(('b', 'a'),);
say $n.raku; # OUTPUT: «("c"=>3).BagHash»
$n.remove('c');
say $n.raku; # OUTPUT: «("c"=>2).BagHash»
마지막 예시에서 볼 수 있듯이, remove 메서드는 BagHash에서 하나의 값을 제거해요. 키 자체를 통째로 없애는 게 아니에요.