2016-03-01 21 views
0

我是一個clojure的完全新手,所以請原諒下面的愚蠢......但我試圖在空間上分割一個字符串矢量,然後從單個序列中獲取所有結果向量矢量中的所有唯一字符串(其中我對序列類型沒有挑剔)。這是我嘗試的代碼。使用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,因此最終這部分代碼將成爲工作流程的一部分,以便高效地處理大量文本數據......獲取它的時間現在是正確的,表現明智的,而且一般來說不是愚蠢的。

謝謝!

回答

7

clojure.set/union在集合上操作,但您給它的序列,而不是(str/split的結果是一個字符串序列)。

(set (mapcat #(str/split % #" ") documents))應該給你你需要的東西。

mapcat會做一個懶惰的「映射和連接」操作。 set會將該序列轉換爲集合,隨着它的發展丟棄重複。

+0

謝謝。我認爲聯合函數會返回一個集合,不管它通過了什麼......不要猜測! –

+2

@PaulGowder這可能有助於考慮具有契約的聯合函數 - 契約的程序員一方將集合傳遞給union,而契約的函數一方則返回一個集合。傳遞媒介而不是集合打破了合同,所以工會可能會或可能不會完成交易的結束。如果它報告了有關其輸入的錯誤可能不那麼令人不安,但隨着時間的推移,您可能會認爲這不是一個問題。 –

+1

@PaulGowder如果你看看源代碼,你會發現'clojure。set/union''將較小集合的元素連接到較大的集合中。因此,例如,'(clojure.set/union(set(range 10))(range 3))'工作,但'(clojure.set/union(set(range 3))n(range 10))''' *序列*'(2 1 0 0 1 2 3 4 5 6 7 8 9)'。正如@Brian所暗示的那樣,你必須將這種行爲視爲實施事故,這種事故在未來可能會發生變化。 – Thumbnail

相關問題