【问题标题】:idiomatic way to use clojure to get set of unique words in vector of strings使用 clojure 获取字符串向量中唯一单词集的惯用方法
【发布时间】:2016-03-01 00:55:35
【问题描述】:

我是 clojure 的新手,所以请原谅下面的愚蠢......但我正在尝试在空格上拆分字符串向量,然后从向量的整个结果向量中获取所有唯一字符串单个序列(我对序列的类型并不挑剔)。这是我尝试过的代码。

(require '[clojure.string :as str])
(require '[clojure.set :as set])
(def documents ["this is a cat" "this is a dog" "woof and a meow"])
(apply set/union (map #(str/split % #" ") documents))

我本来希望这会返回一组独特的单词,即,

#{"woof" "and" "a" "meow" "this" "is" "cat" "dog"}

但它返回一个非唯一词的向量,即,

["woof" "and" "a" "meow" "this" "is" "a" "cat" "this" "is" "a" "dog"]

最终,我只是将它包装在一个集合调用中,即,

(set (apply set/union (map #(str/split % #" ") documents)))

得到了我想要的:

#{"dog" "this" "is" "a" "woof" "and" "meow" "cat"}

但我不太明白为什么会这样。根据docs,联合函数返回一个集合。那我为什么要得到一个向量呢?

第二个问题:另一种方法就是

(distinct (apply concat (map #(str/split % #" ") documents)))

它也返回我想要的,尽管是列表形式而不是集合形式。但是on this prior SO 的一些讨论表明 concat 异常缓慢,可能比 set 操作 (?) 慢。

是这样吗...还有其他理由更喜欢其中一种方法(或第三种方法)吗?

我并不真正关心我是从另一端得到一个向量还是一个集合,但最终会关心性能方面的考虑。我正在尝试通过实际生成对我的文本挖掘习惯有用的东西来学习 Clojure,因此最终这段代码将成为有效处理大量文本数据的工作流程的一部分……是时候获得它了是的,就性能而言,而且只是一般的不愚蠢,就是现在。

谢谢!

【问题讨论】:

    标签: vector clojure set


    【解决方案1】:

    clojure.set/union 对集合进行操作,但您给了它序列(str/split 的结果是字符串序列)。

    (set (mapcat #(str/split % #" ") documents)) 应该可以满足您的需求。

    mapcat 将执行惰性“映射和连接”操作。 set 会将该序列转换为集合,同时丢弃重复的序列。

    【讨论】:

    • 谢谢。我曾假设 union 函数会返回一个集合,无论它通过什么......猜不!
    • @PaulGowder 考虑联合函数可能会有所帮助——合同的程序员方面是将集合传递给联合,而合同的函数方面是返回一个集合。传递向量而不是集合违反了合同,因此联合可能会也可能不会履行其交易的目的。如果它报告了有关其输入的错误,可能不会那么令人不安,但随着时间的推移,您可能会认为这不是一个问题。
    • @PaulGowder 如果查看源代码,您会发现clojure.set/unionconjes 将较小集合的元素放入较大的集合中。因此,例如,(clojure.set/union (set (range 10)) (range 3)) 有效,但 (clojure.set/union (set (range 3))n (range 10)) 返回 sequence (2 1 0 0 1 2 3 4 5 6 7 8 9)。正如@Brian 暗示的那样,您必须将此行为视为实施的意外,将来可能会发生变化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 2020-03-19
    • 1970-01-01
    • 2020-09-12
    • 2011-05-04
    相关资源
    最近更新 更多