2016-05-26 6 views
1

私は少し邪魔になるデータ変換があります。私はClojureで自分自身を表現することができず、私が流暢である私のPythonさえ、まだかなり重いと感じています。ClojureでこのPythonを表現するための機能的/慣用的な方法

私のようなデータ構造を必要とする:

[[1, 2, 3, 5, 6] 
[1, 2, 4, 5, 6]] 

各サブコレクションは、これまでに蓄積された項目に新しいコレクションを作成します。このような構造を生成する

[1, 2, [3, 4], 5, 6] 

。私はただ一つのレベルのネスティングしか期待していない。

私のpythonの試みは、次のようになります。

def foo(path, acc_list=[[]]): 
    for val in path: 
     if not isinstance(val, list): 
      for acc in acc_list: 
       acc.append(val) 
     else: 
      for subval in val: 
       new = acc_list[0][:] 
       new.append(subval) 
       acc_list.append(new) 
      del acc_list[0] 
    return acc_list 

foo([1, 2, [3, 4], 5, 6]) 
# => [[1, 2, 3, 5, 6], [1, 2, 4, 5, 6]] 

私はClojureのソリューションは、(もっと重要なのは)その解決につながった思考こととなるか知りたいのです。

更新

  • int型の順序が明らかに保存されなければならないが、ちょうど例えば、彼らは、必ずしも命じたキーワードや文字列すぎない可能性があります。

  • 入れ子にすると、[1 [2 [3 [4 5] 6] 7] 8]のようにはなりませんが、それ以上は[1 [2 3] 4 [5] 6 [7 8 9]]のように浅くなります。

+0

なぜ結果に2つのリストが含まれていますか? – ssm

答えて

2

Clojureコアライブラリ関数の多くの重要な機能は、遅延(潜在的に無限大)シーケンスを処理する能力です。したがって、私は良い(慣用的な)Clojureソリューションは、無限の遅延シーケンスであるサブシーケンスを含む入力を適切に拡張できると考えています。たとえば:

[:a :b (range) :c] 

は、トップレベルのシーケンスも無限と遅延的に処理することができればそれは素晴らしいことだ

((:a :b 0 :c) (:a :b 1 :c) (:a :b 2 :c) (:a :b 3 :c) ...) 

に展開するべきしかし、私はこのために可能であるとは思いません問題。 (他の誰かが、実質的にこれを処理するための方法を考えることができる場合でも、私は楽しく驚かれることでしょう!)ここで

は私のソリューションです:

(defn expand-subseqs [[x & xs]] 
    (when-not (nil? x) 
    (let [heads (if (sequential? x) x [x]) 
      tails (expand-subseqs xs)] 
     (if-not tails (map vector heads) 
     (for [z tails, y heads] (cons y z)))))) 

ここ直感は、あなたが再帰の尾を扱うということです最初に入力シーケンスを入力し、現在のヘッドの各可能な値をそれぞれの可能なテールの前に追加します。

いくつかのサンプル出力:

user=> (expand-subseqs [1, 2, [3, 4], 5, 6]) 
((1 2 3 5 6) (1 2 4 5 6)) 
user=> (take 5 (expand-subseqs [:a :b (range) :c [true false]])) 
((:a :b 0 :c true) (:a :b 1 :c true) (:a :b 2 :c true) (:a :b 3 :c true) (:a :b 4 :c true)) 

このソリューションの素敵な利点はconsを使用することによって、私たちは実際にそれぞれの結果のための尾の列を表すオブジェクトを再利用するのではなく、各順列のためのシーケンス全体を複製、ということです。たとえば、上記の最後のサンプルでは、​​5つの出力のすべての1つにある(:c true)テールシーケンスが実際には同じオブジェクトです。

+0

簡単な演奏の後、これはチケットのように見えます!ありがとう。 – lsh

1

これを行う方法はほかにもありますが、ここには1つの方法があります。

user.core=> (def x [1, 2, [3, 4], 5, 6]) 
#'user.core/x 
user.core=> (defn create-vecs [x] 
     => (let [sub (first (filter vector? x)) 
     =>   all (remove vector? x)] 
     => (vec (map #(vec (sort (conj all %))) sub)))) 
#'user.core/create-vecs 
user.core=> (create-vecs x) 
[[1 2 3 5 6] [1 2 4 5 6]] 

基本的に、あなたはその後、conjを持つ2つの新しいベクトルを作成するためにそれらの上にマッピングし、ベクトル要素とベクトルマイナスベクトル要素の残りの部分をつかんでいます。 filterremoveリターンリストで、ベクターではないので、余分なvecが必要です。

+0

お返事ありがとうございます。 「1つのレベルのネストを必要とするだけで」私は '[1 [2 [3 4] 5] 6 'タイプの構造体を扱わないことを意味しましたが、私は[1 [2 3] 4 [5 6] 7 ...]型の構造体。しかし、これは思考のための食糧、もう一度ありがとう。 – lsh

+0

ああ、intはちょうど例えば、私は 'get-in'、' assoc-in'と 'updateで使うためのパスを構築するためのパスのリストに展開された短縮表現への文字列をコンパイルしています-in'。明確にするために質問を更新します。 – lsh

関連する問題