位元詩人 [Raku] 程式設計教學:Set、Bag、Mix

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

說明

集合 (Set) 是非線性的單一元素的集合,實作數學上的集合論 (set theory)。在 Perl 5,通常是用雜湊模擬集合,Perl 6 則內建集合容器。BagSet 相似,但會計算該元素出現的次數;MixBag 類似,但允許以非整數來計數;除了用來計數外,BagMixSet 相當類似。

建立集合

建立串列後呼叫 Set 方法即可將其轉為集合。如下例:

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. my $set = (2, 1, 2, 4, 3, 4, 3, 3, 2, 1, 5, 1).Set;
  2.  
  3. $set.elems == 5 or die "Wrong element count";

但是 Set 建立後即不可變動,如果之後要變更其元素,需改用 SetHash,實例如下:

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. my $set = (2, 1, 2, 4, 3, 4, 3, 3, 2, 1, 5, 1).SetHash;
  2.  
  3. $set.elems == 5 or die "Wrong element count";

加入及移除元素

加入元素的方法類似於雜湊,將鍵設為 True 即可;移除時則將鍵設為 False

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. my $set = (1, 2, 3).SetHash;
  2. $set.elems == 3 or die "Wrong element count";
  3.  
  4. # Add a new element.
  5. $set{4} = True;
  6. $set.elems == 4 or die "Wrong element count";
  7.  
  8. # Add a duplicated element, no effect.
  9. $set{3} = True;
  10. $set.elems == 4 or die "Wrong element count";
  11.  
  12. # Remove an element.
  13. $set{1} = False;
  14. $set.elems == 3 or die "Wrong element count";
  15.  
  16. # Remove a non-existing element, no effect.
  17. $set{1} = False;
  18. $set.elems == 3 or die "Wrong element count";

檢查元素存在性

使用 (cont) 可檢查某集合是否包含某元素,如下例:

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. my $set= (1, 2, 3, 4, 5).Set;
  2.  
  3. $set (cont) 1 or die "Wrong status";
  4. ($set (cont) 10) == False or die "Wrong status";

也可以使用 (elem) 檢查某元素是否屬於某集合,如下例:

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. my $set= (1, 2, 3, 4, 5).Set;
  2.  
  3. 1 (elem) $set or die "Wrong status";
  4. (10 (elem) $set) == False or die "Wrong status";

基本上,兩者是同義的,使用自己習慣的方式即可。

集合運算

Perl 6 集合包含一些常見的集合運算,像是聯集 (union)、交集 (intersection)、差集 (difference) 等。實例如下:

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. my $a = (1, 2, 3).Set;
  2. my $b = (2, 4).Set;
  3.  
  4. # Union.
  5. $a (|) $b ~~ (1, 2, 3, 4).Set or die "Wrong status";
  6.  
  7. # Intersection.
  8. $a (&) $b ~~ (2).Set or die "Wrong status";
  9.  
  10. # Difference.
  11. $a (-) $b ~~ (1, 3).Set or die "Wrong status";
  12.  
  13. # Symmetric difference.
  14. $a (^) $b ~~ (1, 3, 4).Set or die "Wrong status";
  15.  
  16. my $c = (2, 3).Set;
  17.  
  18. # Superset.
  19. $a (>=) $c or die "Wrong status";
  20.  
  21. # Strict superset.
  22. $a (>) $c or die "Wrong status";
  23.  
  24. # Subset.
  25. $c (<) $a or die "Wrong status";
  26.  
  27. # Strict subset.
  28. $c (<=) $a or die "Wrong status";

建立 Bag

對串列呼叫 Bag 方法即可建立 Bag,如下例:

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. my $bag = (1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 5, 5).Bag;
  2.  
  3. $bag.elems == 5 or die "Wrong element count";
  4. $bag (cont) 1 or die "Wrong status";

如果建立 Bag 後,需更動其內容,改用 BagHash 即可。

取樣本

由於 Bag 有權重,可設置權重後,對其取樣,如下例:

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. my $bag = (1 => 9, 2 => 5, 3 => 3, 4 => 2, 5 => 1).Bag;
  2.  
  3. loop (my $i = 0; $i < 10; $i++) {
  4.     $bag.roll(5).sort.say;
  5. }

觀察本程式,可發現每次取像的結果都不同,在其中,1 出現的機率最高。

建立 Mix

由於 Mix 的權重是非整數,較常用的方式是直接對其設權重,如下例:

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. my $mix = (1 => 0.8, 2 => 0.1, 3 => 0.05, 4 => 0.02, 5 => 0.01).Mix;
  2.  
  3. loop (my $i = 0; $i < 10; $i++) {
  4.     $mix.roll(10).sort.say;
  5. }

如果建立 Mix 後,需更動其內容,改用 MixHash 即可。基本上,Mix 的用法和 Bag 差不多。

關於作者

位元詩人 (ByteBard) 是資訊領域碩士,喜歡用開源技術來解決各式各樣的問題。這類技術跨平台、重用性高、技術生命長。

除了開源技術以外,位元詩人喜歡日本料理和黑咖啡,會一些日文,有時會自助旅行。