懒惰序列评估计时问题

时间:2014-06-11 19:23:06

标签: clojure

我想从Twitter数据扩展网址,并且(同时)提取他们的域名。我之前在Python中使用请求尝试过这样做,但我想我搞砸了,因为绝大多数URL仍处于“短”状态(bit.ly,goo.gl等)我有Twitter数据存储为JSON。我正在使用clj-http.client :as client来解析网址。到目前为止,我的代码看起来像这样:

(defn expand-urls [urls] (for [url-str urls] 
                     (and url-str (last (:trace-redirects 
                                          (client/get url-str))))))

(def ^:dynamic *domain-pat* (re-pattern #"https?://([\w\.]+)/.*"))

(defn get-domains [urls] (for [url urls] (first (filter #(not= url %1) 
                           (re-find *domain-pat* url)))))

我的Twitter数据格式为[tweet-id [{tweet-data-map} {user-data-map}]],因此(get-in json-data [1 0 "urls"]会返回网址,(get-in json-data [1 0 "domains"])会返回域名。

当我尝试(update-in (update-in js-line [1 0 "urls"] expand-urls) [1 0 "domains"] get-domains)之类的内容时,domains(nil)。我已独立验证我的正则表达式是否有效,所以我怀疑问题是expand-urls返回的延迟序列在get-domains被调用的时间内没有进行评估。令人沮丧的是,(type (doall (expand-urls some-urls)))clojure.lang.LazySeq一样返回(type (doall (doall (expand-urls some-urls))))。我已尝试doall,我尝试将vec添加到expand-urls。似乎都没有用。

这真的是一个懒惰的问题,还是我错过了其他的东西?

2 个答案:

答案 0 :(得分:0)

您可以将解决方案重写为

(defn expand-urls [urls] (
  (mapv #(last (:trace-redirects (client/get %))
    (remove nil? urls)))

假设您不希望在结果中使用nils。 Mapv是惰性映射的严格对应物,总是返回一个向量。

答案 1 :(得分:-1)

解决了!关键是在doall中添加expand-urls

(defn expand-urls [urls] (vec (doall (for [url-str urls]
                       (and url-str (last (:trace-redirects
                                          (client/get url-str))))))))

vec实际上并不是必需的,但我打算重新序列化这些内容,并且不想担心org.clojure/data.json如何翻译列表。)

感谢大家的帮助!我很高兴这里有一个充满活力的clojure支持社区:)