8

以前にPythonを使用してコーディングしたテーブル(作業スケジュール)を作成しようとしています。これは、Clojure言語の良い入門書になると思います。

私はClojure(またはその点ではLisp)の経験がほとんどなく、グーグルでラウンドを行い、試行錯誤を繰り返しましたが、このスタイルのコーディングに頭を悩ませているようには見えません。

これが私のサンプルデータです(将来はsqliteデータベースから取得されます):

(def smpl2 (ref {"Salaried" 
             [{"John Doe" ["12:00-20:00" nil nil nil "11:00-19:00"]}
              {"Mary Jane" [nil "12:00-20:00" nil nil nil "11:00-19:00"]}]
             "Shift Manager"
             [{"Peter Simpson" ["12:00-20:00" nil nil nil "11:00-19:00"]}
              {"Joe Jones" [nil "12:00-20:00" nil nil nil "11:00-19:00"]}]
             "Other"
             [{"Super Man" ["07:00-16:00" "07:00-16:00" "07:00-16:00" 
                       "07:00-16:00" "07:00-16:00"]}]}))

私はこれを最初に使用して、 doseqに移動し、最後にdomap(これはより成功しているようです)と内容をhtmlテーブルにダンプしようとしていました(私の元のPythonプログラムはこれをsqliteデータベースからCOMを使用してExcelスプレッドシートに出力しました)。

これが私の試みです(create-table fn):

(defn html-doc [title & body] 
  (html (doctype "xhtml/transitional") 
    [:html [:head [:title title]] [:body body]])) 

(defn create-table []
  [:h1 "Schedule"]
  [:hr]
  [:table (:style "border: 0; width: 90%")
   [:th "Name"][:th "Mon"][:th "Tue"][:th "Wed"]
   [:th "Thur"][:th "Fri"][:th "Sat"][:th "Sun"]
   [:tr
    (domap [ct @smpl2] 
       [:tr [:td (key ct)]
        (domap [cl (val ct)]
           (domap [c cl]
              [:tr [:td (key c)]]))])
    ]])

(defroutes tstr
  (GET "/" ((html-doc "Sample" create-table)))
  (ANY "*" 404))

これにより、セクション(salaried、managerなど)とセクション内の名前を含むテーブルが出力されます。取得するためだけにさらにdomapを追加する必要があるため、何度もネストしてdomapを悪用しているように感じます。適切な列のシフト時間とコードは、「汚い」感じになっています。

十分な情報が含まれていない場合は、事前にお詫び申し上げます。通常、コーディングについてサポートを求めることはありません。これは、私の最初のSOの質問です:)。

これを行うためのより良いアプローチ、または私が初心者として知っておくべきヒントやコツさえ知っているなら、彼らは間違いなく大歓迎です。

ありがとう。

4

2 に答える 2

4

ある種のネストされたループを回避する方法はありません。しかし、あなたはまったく必要ありませんdomap、Compojureはあなたのためにseqを拡張するのに十分賢いです(時々)。 listそしてmapfor十分です。たとえば、MichałMarczykの答え、または:

(defn map-tag [tag xs]
  (map (fn [x] [tag x]) xs))

(defn create-table []
  (list
   [:h1 "Schedule"]
   [:hr]
   [:table {:style "border: 0; width: 90%"}
    [:tr (map-tag :th ["Name" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun"])]
    [:tr (for [[category people] smpl2]
           (list* [:tr [:td category]]
                  (for [person people
                        [name hours] person]
                    [:tr [:td name] (map-tag :td hours)])))]]))

「seqをマップしてすべてを同じタグでラップする」パターンは十分に一般的であるため、ヘルパー関数を使用することがあります。

Compojureはあなたのために1つのレベルを拡張seqします。したがって、いくつかのものをlistに入れて、タグをHTML出力に順番に表示することができます。これは、h1とhrを表示するために行いました。あなたのコードでは、h1とhrを捨てているだけです。

ただし、拡張されるのは1レベルのみであることに注意してください。リストのリストまたはseqのリストがある場合、外側のseqは展開されますが、内側のseqは展開されません。

user> (println (html (list [:div "foo"] (for [x [1 2 3]] [:div x]))))
<div>foo</div>clojure.lang.LazySeq@ea73bbfd

内側のシーケンスがどのようにCompojureバーフを作るかをご覧ください。compojure.html.gen/expand-seqsこれがどのように機能するかを調べるか、必要に応じて変更/修正してください。

これは、怠惰なseqを返すため、ネストまたはを入れた場合に問題になる可能性がありますfor。ただし、seq-in-a-seqを使用しないようにする必要があります。上記を使用します。との組み合わせでも機能します。他にもたくさんの方法があります。forlistforlist*listhtml

user> (println (html (list* [:div "foo"] (for [x [1 2 3]] [:div x]))))
<div>foo</div><div>1</div><div>2</div><div>3</div>

user> (println (html (list [:div "foo"] (html (for [x [1 2 3]] [:div x])))))
<div>foo</div><div>1</div><div>2</div><div>3</div>
于 2010-03-15T07:43:35.037 に答える
3

コードにいくつかの小さな問題があると思います。以下のコードでそれらを修正しようとしました。Compojure 0.3.2でこれをテストすると、私はあえてそれが機能すると言います。(もちろん、改善が必要なものや、うまくいかないように思われるものは、遠慮なく指摘してください。)

(use 'compojure) ; you'd use a ns form normally

;;; I'm not using a ref here; this doesn't change much,
;;; though with a ref / atom / whatever you'd have to take care
;;; to dereference it once per request so as to generate a consistent
;;; (though possibly outdated, of course) view of data;
;;; this doesn't come into play here anyway
(def smpl2 {"Salaried"      [{"John Doe" ["12:00-20:00" nil nil nil "11:00-19:00"]}
                             {"Mary Jane" [nil "12:00-20:00" nil nil nil "11:00-19:00"]}]
            "Shift Manager" [{"Peter Simpson" ["12:00-20:00" nil nil nil "11:00-19:00"]}
                             {"Joe Jones" [nil "12:00-20:00" nil nil nil "11:00-19:00"]}]
            "Other"         [{"Super Man" ["07:00-16:00" "07:00-16:00" "07:00-16:00" 
                                           "07:00-16:00" "07:00-16:00"]}]})

(defn html-doc [title & body] 
  (html (doctype :xhtml-transitional) ; the idiomatic way to insert
                                      ; the xtml/transitional doctype
        [:html
         [:head [:title title]]
         [:body body]]))

(defn create-table []
  (html
   [:h1 "Schedule"]
   [:hr]
   [:table {:style "border: 0; width: 90%;"}
    [:tr
     [:th "Name"][:th "Mon"][:th "Tue"][:th "Wed"]
     [:th "Thur"][:th "Fri"][:th "Sat"][:th "Sun"]]
    (for [category smpl2]
      [:div [:tr [:td (key category)]] ; for returns just one thing per
                                       ; 'iteration', so I'm using a div
                                       ; to package two things together;
                                       ; it could be avoided, so tell me
                                       ; if it's a problem
       (for [people (val category)]
         (for [person people]
           [:tr
            [:td (key person)]
            (for [hours (val person)]
              [:td hours])]))])]))

(defn index-html [request]
  (html-doc "Sample" (create-table)))

(defroutes test-routes
  (GET "/" index-html)
  (ANY "*" 404))

(defserver test-server
  {:port 8080}
  "/*"
  (servlet test-routes))
于 2010-03-15T01:57:10.047 に答える