我正在尝试创建一个表(一个工作计划),我以前使用python编写过代码,我认为这对我来说是对Clojure语言的一个很好的介绍。
我对Clojure (或lisp在这个问题上的经验)很少,我在google上做过很多次尝试和错误的尝试,但我似乎无法理解这种编码风格。
以下是我的示例数据(将来将来自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"]}]}))我最初尝试使用for来完成这个过程,然后转到doseq,最后是domap (这似乎更成功),并将内容转储到html表中(我最初的python程序使用COM将其从sqlite数据库输出到excel电子表格中)。
下面是我的尝试(创建表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))它输出表中的部分(工资、管理器等)和部分中的名称,我只是觉得我滥用了domap,嵌套了太多次,因为我可能需要添加更多的domap,以便在它们正确的列中获得转换时间,并且代码对其有一种“肮脏”的感觉。
我事先道歉,如果我没有包括足够的信息,我通常不要求帮助编码,这也是我的第一个这么问:)。
如果你知道更好的方法来做这件事,甚至是我作为新手应该知道的技巧或技巧,它们绝对是受欢迎的。
谢谢。
发布于 2010-03-15 07:43:35
没有办法避免某种嵌套循环。但是您根本不需要domap,Compojure很聪明(有时)可以为您展开一个seq。list、map和for就足够了。例如,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为您扩展了一个级别的seq。因此,您可以将一些东西扔到list中,以获取标记,以便在您的HTML中依次显示,我是这样做的,以使h1和hr显示出来。在您的代码中,您只是将h1和hr抛出。
但请注意,它只扩展了一个级别。当您有一个列表或seq列表时,外部seq将展开,而内部seq则不会。
user> (println (html (list [:div "foo"] (for [x [1 2 3]] [:div x]))))
<div>foo</div>clojure.lang.LazySeq@ea73bbfd看看内部seq是如何使Compojure barf的。查看compojure.html.gen/expand-seqs以了解它是如何工作的,如果您愿意的话,可以更改/修复它。
当您在for或for中嵌套list时,这可能是一个问题,因为for返回一个延迟的seq。但你只需要避免吃塞克。我使用上面的list*。list和html的结合也会奏效。还有很多其他的方法。
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-15 01:57:10
我认为您的代码有一些小问题。我已经尝试在下面的代码中纠正它们。在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))https://stackoverflow.com/questions/2444170
复制相似问题