2016-08-03 7 views
3

私は個人市場分析プロジェクトに取り組んでいます。概念的にClojureの複雑なデータ操作

[{:high 1.121455, :time "2016-08-03T05:15:00.000000Z"} 
{:low 1.12109, :time "2016-08-03T05:15:00.000000Z"} 
{:high 1.12173, :time "2016-08-03T04:30:00.000000Z"} 
{:high 1.121925, :time "2016-08-03T00:00:00.000000Z"} 
{:high 1.12215, :time "2016-08-02T23:00:00.000000Z"} 
{:high 1.12273, :time "2016-08-02T21:15:00.000000Z"} 
{:high 1.12338, :time "2016-08-02T18:15:00.000000Z"} 
{:low 1.119215, :time "2016-08-02T12:30:00.000000Z"} 
{:low 1.118755, :time "2016-08-02T12:00:00.000000Z"} 
{:low 1.117575, :time "2016-08-02T06:00:00.000000Z"} 
{:low 1.117135, :time "2016-08-02T04:30:00.000000Z"} 
{:low 1.11624, :time "2016-08-02T02:00:00.000000Z"} 
{:low 1.115895, :time "2016-08-01T21:30:00.000000Z"} 
{:low 1.11552, :time "2016-08-01T11:45:00.000000Z"} 
{:low 1.11049, :time "2016-07-29T12:15:00.000000Z"} 
{:low 1.108825, :time "2016-07-29T08:30:00.000000Z"} 
{:low 1.10839, :time "2016-07-29T08:00:00.000000Z"} 
{:low 1.10744, :time "2016-07-29T05:45:00.000000Z"} 
{:low 1.10716, :time "2016-07-28T19:30:00.000000Z"} 
{:low 1.10705, :time "2016-07-28T18:45:00.000000Z"} 
{:low 1.106875, :time "2016-07-28T18:00:00.000000Z"} 
{:low 1.10641, :time "2016-07-28T05:45:00.000000Z"} 
{:low 1.10591, :time "2016-07-28T01:45:00.000000Z"} 
{:low 1.10579, :time "2016-07-27T23:15:00.000000Z"} 
{:low 1.105275, :time "2016-07-27T22:00:00.000000Z"} 
{:low 1.096135, :time "2016-07-27T18:00:00.000000Z"}] 

が、私は、:high/:lowのペアを一致させる(高 - 低価格帯をうまくしたい:私はこのようになり、市場内のすべての最近の転換点を表すデータ構造を、持っています)と中点(平均は高値の&です)しかし、私は可能なすべてのペアを生成したくありません。私が何をしたいか

コレクション{:high 1.121455, :time "2016-08-03T05:15:00.000000Z"}に第一のアイテムから開始し、コレクションの残りを通じて「ダウン」を歩く、私は次の:high項目を当たるまで、すべての:low項目とペアを作成しています。その次の:highアイテムにヒットしたら、それ以上のペアには興味がありません。この場合、作成されたペアは1つだけです。:highと1番目の:low - 次の(3番目の)アイテムが:highであるため停止します。 1レコードが次

{:price-range 0.000365, :midpoint 1.121272, :extremes [{:high 1.121455, :time "2016-08-03T05:15:00.000000Z"}{:low 1.12109, :time "2016-08-03T05:15:00.000000Z"}]}のようになります。生成された私は、次を打つまで、私はすべての :highアイテムとペアを作成、収集 {:low 1.12109, :time "2016-08-03T05:15:00.000000Z"}で第2項目に移動し、コレクションの残りを通じて「ダウン」を歩くと思います :lowアイテム。この場合、私は :lowと次の5つの :highという項目がすべて連続した5つの新しいレコードを生成します。これらの5つのレコードの最初は、これらの5つのレコードの第二のように

{:price-range 0.000835, :midpoint 1.1215075, :extremes [{:low 1.12109, :time "2016-08-03T05:15:00.000000Z"}{:high 1.121925, :time "2016-08-03T00:00:00.000000Z"}]} 

と次のようになり

{:price-range 0.000064, :midpoint 1.12131, :extremes [{:low 1.12109, :time "2016-08-03T05:15:00.000000Z"}{:high 1.12173, :time "2016-08-03T04:30:00.000000Z"}]} 

ようになります。

その後、私は:lowを取得します。そこで私はそこで止まります。

3番目の項目{:high 1.12173, :time "2016-08-03T04:30:00.000000Z"}に移動して、の次の:highになるまで、すべてのペアで「下に」歩いて歩いてください。この場合、:highの直後にもう1つの:highが続きますので、0ペアが生成されます。 3次で同じ:すべての別の:high

直後れる高いアイテム、次に私は、7項目{:high 1.12338, :time "2016-08-02T18:15:00.000000Z"}に取得し、それは、次の20の:low項目のそれぞれと対を生成しなければなりません。

マイ生成された結果が作成されたすべてのペアのリストのようになります。

[{:price-range 0.000365, :midpoint 1.121272, :extremes [{:high 1.121455, :time "2016-08-03T05:15:00.000000Z"}{:low 1.12109, :time "2016-08-03T05:15:00.000000Z"}]} 
{:price-range 0.000064, :midpoint 1.12131, :extremes [{:low 1.12109, :time "2016-08-03T05:15:00.000000Z"}{:high 1.12173, :time "2016-08-03T04:30:00.000000Z"}]} 
... 

私は、Pythonのようなものを使ってこれを実装した場合、私はおそらく終了しbreakを使用して、ネストされたループのカップルを使用したいです内部ループは私が:lowと対にして、逆の場合は:highを見て停止し、生成されたすべてのレコードを2つのループを横切って配列に累積します。私はちょうどClojureを使用してそれを攻撃する良い方法を働くことができません...

任意のアイデア?

+0

一般的なアドバイス:問題を小さな関数に分割し、その使用法の 'reduce' /' reduced' +例を見てください。 –

+1

これは一般的なインタビューの質問のもう一つの形成です。「ヒストグラムがどれくらいの水分を保持できるか」私は、人々がそれをより抽象的に考えさせるために、代わりにこの絵を使用します。 –

+0

あなたのネストされたループと休憩を使いましょう。Clojureでは、代わりに通常は 'loop'と' recur'を使用します – skrat

答えて

5

あなたはこれを次のように言い換えることができ、すべての最初の:あなたがアイテムを取る必要があるあなたが:high:lowが続いているすべての境界点を、見つける必要が

  1. を、あるいはその逆
  2. の前にバインドし、バインドした後のすべてのアイテムと、次のバインディングがバインドされるまで何かを行います。

    (def data0 [{:a 1} {:b 2} {:b 3} {:b 4} {:a 5} {:a 6} {:a 7}]) 
    

    最初の部分は、入力コレクションに機能が処理アイテムのためにそれの値を変更するたびに分割partition-by機能を使用することによって達成することができます簡単にするために

はのは、以下のデータモデルを使用してみましょう:

user> (def step1 (partition-by (comp boolean :a) data0)) 
#'user/step1 
user> step1 
(({:a 1}) ({:b 2} {:b 3} {:b 4}) ({:a 5} {:a 6} {:a 7})) 

これらのグループを2つおきに操作する必要があります。グループは次のようになります: [({:a 1}){{b 2} {:b 3} {:b 4})] [{{b 2} {:b 3} {:b 4})({5} {6} {7})]

これはpartition機能によって達成される:あなたはグループのすべてのペアのために何かをしなければならない

user> (def step2 (partition 2 1 step1)) 
#'user/step2 
user> step2 
((({:a 1}) ({:b 2} {:b 3} {:b 4})) 
(({:b 2} {:b 3} {:b 4}) ({:a 5} {:a 6} {:a 7}))) 

。あなたがマップでそれを行うことができます:

user> (def step3 (map (fn [[lbounds rbounds]] 
        (map #(vector (last lbounds) %) 
         rbounds)) 
        step2)) 
#'user/step3 
user> step3 
(([{:a 1} {:b 2}] [{:a 1} {:b 3}] [{:a 1} {:b 4}]) 
([{:b 4} {:a 5}] [{:b 4} {:a 6}] [{:b 4} {:a 7}])) 

ていますが、むしろその後、連結リスト、グループ化されたものを必要とすることから、あなたはmapの代わりにmapcatを使用するとよいでしょう:

user> (def step3 (mapcat (fn [[lbounds rbounds]] 
          (map #(vector (last lbounds) %) 
           rbounds)) 
         step2)) 
#'user/step3 
user> step3 
([{:a 1} {:b 2}] 
[{:a 1} {:b 3}] 
[{:a 1} {:b 4}] 
[{:b 4} {:a 5}] 
[{:b 4} {:a 6}] 
[{:b 4} {:a 7}]) 

私たちが望む結果だという(マップの代わりにベクトルを生成するだけなので、ほぼあります)。

今はスレッドマクロでそれを飾り立てることができます:あなたはまったく同じ結果が得られる

(->> data0 
    (partition-by (comp boolean :a)) 
    (partition 2 1) 
    (mapcat (fn [[lbounds rbounds]] 
       (map #(vector (last lbounds) %) 
        rbounds)))) 

を。あなたのデータに適用

は、それが(別の結果生成FNで)

user> (defn hi-or-lo [item] 
     (item :high (item :low))) 
#'user/hi-or-lo 
user> 
(->> data 
    (partition-by (comp boolean :high)) 
    (partition 2 1) 
    (mapcat (fn [[lbounds rbounds]] 
       (let [left-bound (last lbounds) 
        left-val (hi-or-lo left-bound)] 
       (map #(let [right-val (hi-or-lo %) 
          diff (Math/abs (- right-val left-val))] 
         {:extremes [left-bound %] 
          :price-range diff 
          :midpoint (+ (min right-val left-val) 
             (/ diff 2))}) 
         rbounds)))) 
    (clojure.pprint/pprint)) 

をほぼ同じになり、それは次のように出力されます答えとして

({:extremes 
    [{:high 1.121455, :time "2016-08-03T05:15:00.000000Z"} 
    {:low 1.12109, :time "2016-08-03T05:15:00.000000Z"}], 
    :price-range 3.6500000000017074E-4, 
    :midpoint 1.1212725} 
{:extremes 
    [{:low 1.12109, :time "2016-08-03T05:15:00.000000Z"} 
    {:high 1.12173, :time "2016-08-03T04:30:00.000000Z"}], 
    :price-range 6.399999999999739E-4, 
    :midpoint 1.12141} 
{:extremes 
    [{:low 1.12109, :time "2016-08-03T05:15:00.000000Z"} 
    {:high 1.121925, :time "2016-08-03T00:00:00.000000Z"}], 
    :price-range 8.350000000001412E-4, 
    :midpoint 1.1215074999999999} 
{:extremes 
    [{:low 1.12109, :time "2016-08-03T05:15:00.000000Z"} 
    {:high 1.12215, :time "2016-08-02T23:00:00.000000Z"}], 
    :price-range 0.001060000000000061, 
    :midpoint 1.12162} 
{:extremes 
    [{:low 1.12109, :time "2016-08-03T05:15:00.000000Z"} 
    {:high 1.12273, :time "2016-08-02T21:15:00.000000Z"}], 
    :price-range 0.0016400000000000858, 
    :midpoint 1.12191} 
{:extremes 
    [{:low 1.12109, :time "2016-08-03T05:15:00.000000Z"} 
    {:high 1.12338, :time "2016-08-02T18:15:00.000000Z"}], 
    :price-range 0.0022900000000001253, 
    :midpoint 1.1222349999999999} 
{:extremes 
    [{:high 1.12338, :time "2016-08-02T18:15:00.000000Z"} 
    {:low 1.119215, :time "2016-08-02T12:30:00.000000Z"}], 
    :price-range 0.004164999999999974, 
    :midpoint 1.1212975} 
{:extremes 
    [{:high 1.12338, :time "2016-08-02T18:15:00.000000Z"} 
    {:low 1.118755, :time "2016-08-02T12:00:00.000000Z"}], 
    :price-range 0.004625000000000101, 
    :midpoint 1.1210675} 
... 

複雑なデータ操作」についての質問"、私はあなたがすべてのコレクションの操作機能をclojureコアから調べて、それらのアプリケーションにすべてのタスクを分解しようとアドバイスします。それ以上のものが必要なケースはあまりありません。

+0

素晴らしい答え - レッスンありがとう!私はあなたが問題を一連の小さな問題に分解したかどうかについてのあなたの考えに従うことができます。私はClojureデータ操作の理解に最低2レベルは達しました。今私はあなたが提案したことをやるために立ち去っています - clojure.coreのコレクション操作関数のセットを使って(やり直して)、あなたが明確に概説したように一緒にぶら下がっていく方法を吸収しようとします – monch1962

関連する問題