トラック
/
Factor
Factor
/
演習
/
ポエトリークラブ
ポエトリークラブ

ポエトリークラブ

学習演習

はじめに

素集合(union-find構造)は、値の集まりを重なりのないグループに分割した状態で保持し、ある1つの問いにすばやく答えます。その問いとは、この2つの値は同じグループにあるかどうかです。これはdisjoint-setsボキャブラリーにあります。

素集合を組み立てる

<disjoint-set>は空の構造を組み立てます。値(アトム)は、add-atomで1つずつ追加するか、add-atomsでシーケンスからまとめて追加します。それぞれのアトムは最初、自分だけのグループに入っています。

<disjoint-set> ( -- disjoint-set )
add-atom       ( atom disjoint-set -- )
add-atoms      ( seq disjoint-set -- )
USING: disjoint-sets ;

<disjoint-set>
{ 1 2 3 } over add-atoms   ! 1, 2 and 3 each in their own group

素集合はミュータブルです。add-atom、add-atoms、equateは、新しいものを返すのではなく、その場で書き換えます。これらのワードが素集合を消費したあとに、その素集合を再びスタックに戻したいときはkeepが便利です。

グループを統合する

equateは、そのアトムが属する2つのグループを統合します。統合は推移的です。2つのアトムを統合し、次にそのどちらかを3つ目のアトムと統合すると、3つとも同じグループになります。

equate ( atom1 atom2 disjoint-set -- )

代表元

それぞれのグループには、標準となるメンバーが1つあり、それを代表元と呼びます。representativeはそれを返します。2つのアトムが同じグループに属するのは、それらの代表元が等しいときに限られます。

representative ( atom disjoint-set -- representative )
USING: disjoint-sets ;

<disjoint-set>
{ 1 2 3 } over add-atoms
1 2 pick equate
1 over representative .   ! => 1
2 over representative .   ! => 1   (same representative as 1)
3 over representative .   ! => 3   (still on its own)

グループがどのアトムを代表元に選ぶかは内部の詳細です。特定のアトムが選ばれることを当てにしてはいけません。当てにしてよいのは、同じグループの2つのアトムの代表元が一致していることだけです。

説明

地元の詩人会が新しいシーズンを迎えます。詩人たちは会に加わり、そのうちの2人が一緒に詩を書くと、2人は同じ創作サークルの一員になります。会は、誰が誰と同じサークルなのかを把握したいと考えており、それを管理するワードを書くよう依頼されました。

素集合がうってつけです。詩人ひとりひとりが要素で、創作サークルがグループになります。

1. 会を立ち上げる

new-clubを定義します。詩人の並びを受け取り、すべての詩人を登録した新しい素集合を返します。各詩人は、それぞれ自分だけの創作サークルから始まります。

{ "Keats" "Byron" "Dickinson" } new-club
! => a disjoint set holding the three poets

2. 共作を記録する

collaborateを定義します。詩人を2人と会を受け取ります。2人の詩人の創作サークルを統合して会を返すので、共作を次々と記録できます。

{ "Keats" "Byron" "Dickinson" } new-club
"Keats" "Byron" rot collaborate
! => the club, with Keats and Byron now in one circle

3. 詩人のサークルを探す

circle-ofを定義します。詩人と会を受け取り、その詩人の創作サークルの代表を返します。同じサークルに属する2人の詩人は、いつも同じ代表を返します。

{ "Keats" "Byron" "Dickinson" } new-club
"Dickinson" swap circle-of
! => "Dickinson"   (still in a circle of their own)

4. 同じサークル?

same-circle?を定義します。詩人を2人と会を受け取り、2人の詩人が同じ創作サークルに属していればtを、そうでなければfを返します。組み込みの同値テストを使うのではなく、詩人の代表を比較します。

{ "Keats" "Byron" "Dickinson" } new-club
"Keats" "Byron" rot collaborate
dup [ "Keats" "Byron" ] dip same-circle? .      ! => t
    [ "Keats" "Dickinson" ] dip same-circle? .  ! => f
GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
Factor Exercism

ポエトリークラブを始める準備はできましたか?

Exercismに登録すれば、47個のコンセプト163個の演習、そして本物の人間によるメンタリングとともに、Factorを学んでマスターできます。すべて無料です。