Iconミニ講座4(フィルター)
今回は、正整数の部分和への分解で、結構な数のパターンが生成されますので、
これに制限を掛けます。 分割数の制限と最小数の制限を付けられるようにします。
前回の n_divd.icn に制限を付ける処理を追加しても良いのですが、降順のみの
制限を付けるだけで結構面倒で、これを修正する気が起きません。
そこで、n_divd.icnはそのままにして、n_divdを呼ぶ方で制限を付けようと思い
ます。
あるプログラムの処理結果を、別のプログラムが加工して、更に別のプログラムに
渡すことを、フィルターと言いますので、その類のプログラム構成のやり方となり
ます。 こんな格好の構成です。
+----------------+ +--------------+ +--------------+
| n_divd | | n_divdf | | main |
| 正整数分割生成 | ---> | 分割数制限 | ---> | 結果を使用 |
| | | 最小数制限 | | |
| | | フィルター | | |
| generator | | generator | | |
+----------------+ +--------------+ +--------------+
-----^ N_DIVDF.ICN ( date:03-08-20 time:23:48 ) ------------<cut here
####################
# 正整数分割 分割数・最小数制限付き
####################
# n_divdf.icn Rev.1.0 2003/08/20 windy 風つかい H.S.
####################
# Usage n_divdf 正整数 最大分割数 最小数
# 与えられた数字を部分和に分解する。結果は降順の分解のみ。
# 例:5->[5],[4,1],[3,2],[3,1,1],[2,2,1],[2,1,1,1],[1,1,1,1,1]
# この中で、最大分割数、最小数の制限に合うものを出力する。
# This file is in the public domain.
procedure main(args)
Usage := "n_divd 正整数 最大分割数 最小数"
if *args < 1 then stop(Usage) # コマンドライン引数が無ければ Usage表示
if args[1] < 1 then stop(Usage) # 正数でなければ Usage表示
n := args[1] # ↓defaultはなるべく生成パターンが少なくなるよう
ndiv := \args[2] | 1 # defaultの最大分割数は、1(分割せず)
nmin := \args[3] | *n # defaultの最小数は、分割される数そのもの
write(n," を、最大分割数 ",ndiv,"、最小数 ",nmin," にて分割")
# ↓正整数分割 generatorから順次結果を取り出し
every L := n_divdf(n,ndiv,nmin) do show_sl(L)
# ↑listの内容を表示する
end
####################
# 正整数分割 generator
####################
# 5=3+2 等に数字分割する。この procedureは n_divdを呼びフィルターを掛けている。
# 分割パターンが多すぎる時に、制限をかけるために使用。
# arg [1]: 分割する元の数
# [2]: 最大分割数
# [3]: 最小数
# value : list
procedure n_divdf(r,ndiv,nmin)
every L := n_divd(r) do { # r の分割結果を取り出し
if *L <= ndiv then { # 分割数チェック(listのサイズチェック)
if L[*L] >= nmin then suspend L # 最小数チェック(降順に入っているので
} # 末尾の要素をチェック)
}
end
####################
# 正整数分割 generator
####################
# 5=3+2 等に分割する。分割は降順のみ許す。(例 5=2+3は除外)
# arg [1]: 分割される元の数(再帰の場合は、前の処理の余り)
# [2]: 最大数 (5=2+2+1 の場合に、最初の 2の時 3が余るが、再帰して 3の
# 分割を始める時、3からではなく 2から始めるための細工。降順手当。)
# value : 分解結果の数。listに格納
# Usage : every L := n_divd(r) do ...
procedure n_divd(r,max)
/max := r # 指定無きは、分割される元の数そのもの
if r < 1 then fail # 念のため
if r = 1 then return [1] # 再帰終了
# r >= 2 の場合
if r > max then rs := max # 分割(取り去る)数の最大数の設定。
else rs := r # 分割される数か 最大数指定の 小さい方
every i := rs to 1 by -1 do { # 上記指定数〜1迄、順に−1しながら
rr := r -i # 新たな余り
if rr = 0 then suspend [i] # 余りが無ければ
# 余りがあれば、再帰処理
else if rr > i then suspend [i] ||| n_divd(rr,i) # 余りが大き過ぎる時
else suspend [i] ||| n_divd(rr)
}
end
# 以下は、Icon入門講座より
####################
# listの 内容表示
####################
# arg : list
# value : null
# Usage : show_sl(L)
# 最終的に stringか numberが要素であること
# Icon入門講座(13),Icon入門講座3(15)
procedure show_sl(list)
# listの内容表示(test/表示用)
every writes(" ",!list)
write()
return
end
-----$ N_DIVDF.ICN ( lines:86 words:320 ) ------------------<cut here
n_divdf 9 3 3 >eee とすると、結果はこうなります。 相当、制限が付けられ
ますね。
-----^ EEE ( date:03-08-21 time:00:00 ) --------------------<cut here
9 を、最大分割数 3、最小数 3 にて分割
9
6 3
5 4
3 3 3
-----$ EEE ( lines:5 words:13 ) ----------------------------<cut here
さて、次回は、まとめです。
風つかい(hshinoh@...)
IconのWWWは、 http://www.cs.arizona.edu/icon/
UniconのWWWは、http://unicon.sourceforge.net/index.html
BGM: Battery's not included / 森山威男&杉本喜代志