2つの表を比較する
また人様のネタを頂戴する。
整数からなる列がふたつあり、それぞれ 表A、表B とする。それぞれ片側にしかない数字を抽出しようというものだ。
vbaHaskellで短く書くとこうなる。ただし値ではなく、ある/ないの結果を 1 / 0 で表示した。
ab = unZip(mapF(p_equal_range(表B), 表A)) ba = unZip(mapF(p_equal_range(表A), 表B)) printM zipWith(p_less, ab(0), ab(1)) printM zipWith(p_less, ba(0), ba(1))
equal_range は lower_bound と upper_bound の結果を同時に出力する関数で、それぞれソート済み配列の中から検索対象の値が存在する「先頭」および「最後の次」の場所を求めるものだ。
(モジュールはここ → https://github.com/mYmd/VBA/blob/master/Haskell_5_sort.bas)
言い換えると目的とする値は [ lower_bound, upper_bound ) の中にあり、その個数は upper_bound - lower_bound で求められる。存在するかどうかだけなら、lower_bound < lower_bound が成り立つかどうかで判定できるので less 関数を使って計算している。
上のコードを少し冗長に書いてみる。
' //ふたつの表を表示してみる printM 表A 1 2 3 5 6 6 6 7 13 14 15 19 26 30 30 printM 表B 1 4 5 7 7 8 9 10 10 11 12 13 17 17 20 20 20 24 27 30 ' //AからBを見たときの equal_range equal_range_from_A_to_B = mapF(p_equal_range(表B), 表A) ' //BからAを見たときの equal_range equal_range_from_B_to_A = mapF(p_equal_range(表A), 表B) ' //equal_range_from_A_to_Bを表示してみる(説明は後からの手書き) for each z in equal_range_from_A_to_B : printM z: next z 0 1 <= 1は表B(0)にある (0 < 1だから) 1 1 <= 2は表Bにない (1 = 1だから) 1 1 <= 3は表Bにない 2 3 <= 5は表B(2)にある 3 3 <= 6は表Bにない 3 3 <= 6は表Bにない 3 3 <= 6は表Bにない 3 5 <= 7は表B(3), B(4)にある 11 12 <= 13は表B(11)にある 12 12 <= 14は表Bにない 12 12 <= 15は表Bにない 14 14 <= 19は表Bにない 18 18 <= 26は表Bにない 19 20 <= 30は表B(19)にある 19 20 <= 30は表B(19)にある ' //equal_range_from_B_to_Aを表示してみる(説明は後からの手書き) for each z in equal_range_from_B_to_A : printM z: next z 0 1 <= 1は表A(0)にある 3 3 <= 4は表Aにない 3 4 <= 5は表A(3)にある 7 8 <= 7は表A(7)にある 7 8 <= 7は表A(7)にある 8 8 <= 8は表Aにない 8 8 <= 9は表Aにない 8 8 <= 10は表Aにない 8 8 <= 10は表Aにない 8 8 <= 11は表Aにない 8 8 <= 12は表Aにない 8 9 <= 13は表A(8)にある 11 11 <= 17は表Aにない 11 11 <= 17は表Aにない 12 12 <= 20は表Aにない 12 12 <= 20は表Aにない 12 12 <= 20は表Aにない 12 12 <= 24は表Aにない 13 13 <= 27は表Aにない 13 15 <= 30は表A(13), A(14)にある ' //結果を表示してみる ab = unzip(equal_range_from_A_to_B) printM zipWith(p_less, ab(0), ab(1)) 1 0 0 1 0 0 0 1 1 0 0 0 0 1 1 ba = unzip(equal_range_from_B_to_A) printM zipWith(p_less, ba(0), ba(1)) 1 0 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1
なお、unZip 関数はジャグ配列をほどいて以下のように再構成する関数である。
( (0, 1), (1, 1), (1, 1), (2, 3), (3, 3), (3, 3), (3, 3), (3, 5), (11, 12), (12, 12), (12, 12), (14, 14), (18, 18), (19, 20), (19, 20), ) unZip ↓ ( (0, 1, 1, 2, 3, 3, 3, 3, 11, 12, 12, 14, 18, 19, 19), (0, 1, 1, 3, 3, 3, 3, 5, 12, 12, 12, 14, 18, 20 ,20) )
上の表Aと表Bはランダム数値を生成するモジュールで作った。
VBAHaskellの紹介 その25(乱数生成:メルセンヌ・ツイスタ mt19937) - Qiita
' //ランダムな整数を作ってソートしておく 表A = uniform_int_dist(15, 1, 30) : permutate 表A, sortIndex(表A) ' //[1~30]から15個 表B = uniform_int_dist(20, 1, 30) : permutate 表B, sortIndex(表B) ' //[1~30]から20個