esp*_*eed 1 java iterator clojure sequence
我正在尝试将词性功能的输出传递到index-words函数中,并使用( - >)线程宏打印结果输出:
(defn parts-of-speech []
(seq (. POS values)))
(defn index-words [pos]
(iterator-seq (. dict getIndexWordIterator pos)))
(-> (parts-of-speech) index-words println)
Run Code Online (Sandbox Code Playgroud)
但是index-words func返回一个iterator-seq,我不知道如何在这个上下文中迭代它,因为我是Clojure的新手.
编辑:根据建议更新代码.
更新:
感谢@kotarak和@ jayunit100的回答以及来自@ sw1nn和@ marko-topolnik的评论,我至少有两个有效的变体:
(->> (parts-of-speech) (map index-words) (map println) doall)
(doseq [w (map index-words (parts-of-speech))]
(println w))
Run Code Online (Sandbox Code Playgroud)
我来自一个命令性的背景,我的这个问题的目标是理解线程宏,试图编写更多惯用的Clojure(在尝试使用线程宏之前,我使用multiple doseq和lets 循环遍历每个序列).
从评论来看,似乎线程宏可能不是最惯用的方式,但我仍然希望看到如何使它工作,所以我可以填补这个理解的空白.
此外,(parts-of-speech)返回一个包含四个项目的序列,如果您执行a (println (count w))而不是(println w),则可以看到它打印四个序列的计数而不是一个连续序列:
(doseq [w (map index-words (parts-of-speech))]
(println (count w)))
;= 117798
;= 11529
;= 21479
;= 4481
Run Code Online (Sandbox Code Playgroud)
你如何修改上面的内容来打印一个连续的单词流而不是打印四个序列的内容?
BTW:上面的代码包含了MIT Java WordNet库(http://projects.csail.mit.edu/jwi/).
seqs和iterator-seq之间的关系如下:a iterator-seq从迭代器创建seq.
请原谅这里的冗长,但要回答"如何迭代iterator-seq的输出"的问题,我们必须首先明确定义为什么需要调用iterator-seq来开始:
在Clojure中,您不会发现自己需要经常创建iterator-seq对象.因为clojure可以非常方便地处理"Iterable"java对象的迭代(参见:http://clojuredocs.org/clojure_core/clojure.core/iterator-seq).但是,迭代器本身不可迭代.
要完全理解这一点,您需要了解Iterables和Iterators之间的区别,这主要是因为在Java世界中保持语义一致和直接:为什么Java的Iterator不是Iterable?.
什么是'seq'?
在clojure中,有一个比java的Iterator接口更高的抽象,这是ISeq的接口.iterator-seq为我们创建了一个ISeq.这个ISeq对象现在可以被许多Clojure函数使用,这些函数对顺序的项目列表进行操作.
user=> (iterator-seq (.iterator (new java.util.ArrayList ["A" "B"])))
("A" "B")
;Thus, we now have an ISeq implementation derived from an iterator.
Run Code Online (Sandbox Code Playgroud)
因此,你的"iterator-seq"函数正在为你创建一个来自java迭代器的Clojure"序列".澄清 - 当我们在非可迭代对象上调用"iterator-seq"时的错误消息是提供信息的:
user=> (iterator-seq "ASDF")
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Iterator (NO_SOURCE_FILE:0)
Run Code Online (Sandbox Code Playgroud)
这告诉我们"iterator-seq"函数需要java.util.Iterator作为输入.
您可能遇到的下一个逻辑问题是:
为什么我们需要从迭代器创建序列?seq抽象与java中的迭代器抽象有何不同?
Iterable接口并不像Clojure的ISeq那样抽象.例如,考虑字符串.显然,字符串是顺序的.然而,它们在Java中不可迭代.数组也是如此.
来自clojure网站:
"seq适用于Java参考数组,Iterables和Strings.由于库的其余部分都是基于这些函数构建的,因此非常支持在Clojure算法中使用Java对象."
因此,你的iterator-seq的目的是将你的迭代器对象"包装"成一个序列抽象,它将能够利用所有的clojures功能好东西.
定义iterator-seq的作用
来自http://clojure.org/sequences:
"seq函数产生适合集合的ISeq实现."
在您的情况下,我们可以这样说:
"iterator-seq函数为getIndexWordsIterator生成了一个ISeq实现".
最后:我如何迭代seq?
鉴于背景,这个问题需要仔细回答.
迭代肯定是可能的 - 但不是clojure中的主要问题,它可能不是你真正想要的.由于iterator-seq已经为我们创建了一个SEQ,现在我们可以使用Clojure的一个函数运算符(即列表推导,映射函数等)来使用该seq.这消除了手动迭代的需要.
例如,通常,我们遍历列表以查找值.在clojure中,我们可以使用filter函数找到一个值:
user=> (filter #(= \A %) (seq "ABCD"))
(\A)
Run Code Online (Sandbox Code Playgroud)
我们可能希望通过遍历每个对象将函数应用于多个对象,而不是过滤,将结果存储在新集合中.同样,这需要 - 不要通过Clojure中的显式迭代来完成:
user=> (map #(.hashCode %) (seq "ABCZ"))
(65 66 67 90)
Run Code Online (Sandbox Code Playgroud)
最后,如果您真的需要手动迭代您的集合,您可以使用Loop-recur构造手动,尾递归遍历您的序列,一次一个元素:http://clojure.org/functional_programming#Functional%20Programming - 递归%20Looping.或者您可以使用标准递归调用.
| 归档时间: |
|
| 查看次数: |
1337 次 |
| 最近记录: |