2011-12-27 12 views
3

リストを与えられたら、私は "境界関数"を使ってクラスターに分割したいと思います。そのような機能は、リストの2つの連続した要素をとり、それらが同じクラスタに属するべきかどうかを決定する。境界関数を使用してリストをクラスタリングする

だから、基本的に、私はこのような何かしたい:それはHoogleで、この型宣言がもたらした

clusterBy :: (a -> a -> Bool) -> [a] -> [[a]] 

ghci> farAway x y = abs (x - y) > 10 
ghci> clusterBy farAway [1, 4, 18, 23, 1, 17, 21, 12, 30, 39, 48] 
[[1, 4], [18, 23], [1], [17, 21, 12], [30, 39, 48]] 

を見上げるだけgroupBy私はそれを考慮要素の順序を取ることはありません(必要正確に何されていません)。

似たようなライブラリ関数はありますか?または、代わりに、きれいに、つまりテール再帰ループに頼らずに実装する方法はありますか?

EDIT:参考のために、私は調理するために管理の実装は次のとおりです。

clusterBy :: (a -> a -> Bool) -> [a] -> [[a]] 
clusterBy isBoundary list = 
loop list [] [] 
    where 
     loop (first:rest) [] result = loop rest [first] result 
     loop [email protected](next:rest) cluster result = 
      if isBoundary (head cluster) next then 
       loop list [] ((reverse cluster):result) 
      else 
       loop rest (next:cluster) result 
     loop [] [email protected](_:_) result = cluster:result 
     loop _ _ result = result 
+0

テール再帰ループがきれいでないのはなぜですか?このような単純な解決策を避ける目的は何ですか? –

+0

私は思いついた末尾再帰バージョンを追加して、質問を編集しました。私は終端条件の数と全体的な冗長さに不満を持っています。率直に言えば、それはまったく有害ではないように見えます。基本的に、機能的な言語に強制される必須のバージョンです。 – Xion

答えて

4

は何をしたい、このですか?

clusterBy :: (a -> a -> Bool) -> [a] -> [[a]] 
clusterBy isDifferentCluster = foldr f [] 
    where f x (ys @ (y : _) : yss) | not (isDifferentCluster x y) = (x : ys) : yss 
     f x     yss         = [x]  : yss 
関数の引数の意味は、おそらく逆にする必要があります

(その引数は、同じクラスタとそうでない場合はfalseにする必要があるとき、すなわちtrueを返す)が、私はあなたが尋ねた形でそれを与えてくれました。

+0

パーフェクト。私は折り目を使用しようとしましたが、このような複雑なパターンマッチングは考えていませんでした。ありがとう! – Xion

関連する問題