2016-07-05 14 views
1

これは簡単ですが、予想よりも難しいと感じています。要素が出現するたびに分割ベクトル

[0 1 2 0 1 2 0 1]が与えられた場合、各出現が2の後に分割します。

結果は[[0 1 2] [0 1 2] [0 1]]と似ているはずです。

split機能は最初のインスタンスでのみ分割されます。私の想像力はまた、これを達成するためにpartition関数を使用する方法にも制限があります。

+0

必要です:バリアント、および6〜10倍速くpartitionバリアントより)

また、あなたはClojureののシーケンス動作させる機能がないと遅延コレクションを返し、いくつかのマイナーな改良とよりclojurishすることができます数字のベクトルまたは任意のオブジェクトのベクトル? – OlegTheCat

答えて

2

(いくつかのケースでは欠陥があれば@magosソリューションが)以前のソリューションはOKですが、この関数は(それは私が推測する、むしろ一般的である)ユーティリティとして使用する場合、私は古典的な反復的なアプローチを使用します。

REPLで
(defn group-loop [delim coll] 
    (loop [res [] curr [] coll (seq coll)] 
    (if coll 
     (let [group (conj curr (first coll))] 
     (if (= delim (first coll)) 
      (recur (conj res group) [] (next coll)) 
      (recur res group (next coll)))) 
     (if (seq curr) 
     (conj res curr) 
     res)))) 

user> (map (partial group-loop 2) 
      [[] 
      nil 
      [1 2 3 1 2 3] 
      [1 2 3 1 2 3 2] 
      [2 1 2 3 1 2 3] 
      [1 3 4 1 3 4]]) 

;;([] [] 
;; [[1 2] [3 1 2] [3]] 
;; [[1 2] [3 1 2] [3 2]] 
;; [[2] [1 2] [3 1 2] [3]] 
;; [[1 3 4 1 3 4]]) 

それは少しも冗長に見えますが、それはまだいくつかのかなり重要な利点があります:すべての最初は、それは(私はむしろ詐欺よりもプロを見つける。)古典の一種です、秒:それは速いです(私のベンチマークによると約3倍速いあなたが分割する

(defn group-lazy [delim coll] 
    (loop [curr [] coll coll] 
    (if (seq coll) 
     (let [curr (conj curr (first coll))] 
     (if (= delim (first coll)) 
      (cons curr (lazy-seq (group-lazy delim (rest coll)))) 
      (recur curr (next coll)))) 
     (when (seq curr) [curr])))) 

user> (map (partial group-lazy 2) 
      [[] 
      nil 
      [1 2 3 1 2 3] 
      [1 2 3 1 2 3 2] 
      [2 1 2 3 1 2 3] 
      [1 3 4 1 3 4]]) 

;;(nil nil 
;; ([1 2] [3 1 2] [3]) 
;; ([1 2] [3 1 2] [3 2]) 
;; ([2] [1 2] [3 1 2] [3]) 
;; [[1 3 4 1 3 4]]) 
1

2つのpartitionバリアントを組み合わせて1つの方法を示します。最初にpartition-byを使用して2のインスタンスで除算し、partition-allを使用して2つと2つのパーティションを取り出し、concatを使用して結合します。

(->> [0 1 2 0 1 2 0 1] 
    (partition-by (partial = 2))    ;;((0 1) (2) (0 1) (2) (0 1)) 
    (partition-all 2)       ;;(((0 1) (2)) ((0 1) (2)) ((0 1))) 
    (mapv (comp vec (partial reduce concat)))) ;;[[0 1 2] [0 1 2] [0 1]] 

が、入力が2で始まる場合返さパーティションはまた、2Sで始まるとしてここではそれらに終了しないことに注意してください。

0

ここに行く、すべての入力のために要求されるように動作します:

(reduce #(let [last-v (peek %1)] 
      (if (= 2 (last last-v)) 
      (conj %1 [%2]) 
      (conj (pop %1) (conj last-v %2)))) 
     [[]] 
     [2 2 0 1 2 3 4 2 2 0 1 2 2]) 

=> [[2] [2] [0 1 2] [3 4 2] [2] [0 1 2] [2]] 

マゴスがエレガントな解決策を持っていますが、彼が言及して、それは、残念ながら完全ではありません。だから、上記はreduceを使って仕事をするべきです。

最近追加された要素を見ます。 2だった場合は、新しいサブベクトル((conj %1 [%2]))を作成します。それ以外の場合は、最後のサブベクトルに追加します。本当にシンプル。 partitionsplitのような既存の関数は、可能な限り再利用するのに最適ですが、最適な解決策はカスタム関数であることがあります。この場合、実際にはきれいです。

関連する問題