2011-11-04 8 views
4

나는 Clojure를 배우고 있으며 운동으로 unix "comm"명령과 같은 것을 쓰고 싶었다.Clojure에서 파일의 내용을 읽는 가장 좋은 방법

이렇게하려면 각 파일의 내용을 세트로 읽은 다음 difference/intersection을 사용하여 독점/공통 파일을 표시하십시오. 서열에 읽기/라인 파일의 내용

(def contents (ref #{})) 
(doseq [line (read-lines "/tmp/a.txt")] 
    (dosync (ref-set contents (conj @contents line)))) 

(나는 오리 스트림을 사용하고 있습니다 : REPL - 많은 시간 후

가 나는 세트 작성 부분에 대해이 같은 것을 함께했다).

이것은 모든 종류의 함수형 프로그래밍 또는 lisp/Clojure에서의 첫 번째 찌르기입니다. 예를 들어, 내가 세트에 conj를했을 때, 세트가 여전히 비어있는 이유를 이해할 수 없었습니다. 이것은 심판에 대해 배울 수있게 해줍니다.

  1. 더 나은 Clojure/기능적 방법이 있습니까? ref-set을 사용하여 비 기능적 사고 방식으로 코드를 비틀 렸을 때입니까, 아니면 코드를 어떻게 수행해야 할 것인가에 따른 코드입니까?
  2. 이미이 작업을 수행하는 라이브러리가 있습니까? 이것은 상대적으로 평범한 일처럼 보이기를 바라지 만 나는 그런 것을 찾을 수 없습니다.
+0

브라이언 카퍼의 대답이 좋습니다. 오리 스트림을 사용하지 마십시오. 'clojure.core'와'clojure.java.io'에 대부분의 기능이 포함되어 사용되지 않습니다. –

+0

당신의 코멘트에 관하여 세트가 "아직도 비어 있었다"; 당신이 변덕스러운 행동을 기대하고있는 것처럼 들리 네요. 클로저에서 데이터 유형은 변경 불가능하다는 것을 기억하십시오. 콜렉션 빌드는 재귀 적으로 수행되므로, Brian Carper ('into '는 내부적으로'reduce'를 사용함)에 표시된 것처럼'reduce'를 사용합니다. –

+0

@DaveRay 오리 스트림의 상태를 알지 못했습니다. 정보 주셔서 감사합니다. – rifboy

답변

7

Clojure의 1.3 :

user> (require '[clojure.java [io :as io]]) 
nil 
user> (line-seq (io/reader "foo.txt")) 
("foo" "bar" "baz") 
user> (into #{} (line-seq (io/reader "foo.txt"))) 
#{"foo" "bar" "baz"} 

line-seq 당신에게 순서의 각 항목은 파일의 라인 게으른 순서를 제공합니다.

into 모두를 세트로 덤프합니다. 오히려 doseq와 심판보다 (세트에 의해 각 항목 하나를 추가)을하려고했는지하려면, 당신은 할 수 :

user> (reduce conj #{} (line-seq (io/reader "foo.txt"))) 
#{"foo" "bar" "baz"} 

주 유닉스 comm 가능성이 두 개의 정렬 된 파일을 비교하는 것이 교차로를 설정하는 것보다 파일을 비교하는 더 효율적인 방법입니다.

편집 :

user> (with-open [f (io/reader "foo.txt")] 
     (into #{} (line-seq f))) 
#{"foo" "bar" "baz"} 
+2

'with-open'에서 해당 리더를 포장하는 것을 잊지 마십시오 :) –

+0

@BrianCarper 고마워, 정말 도움이됩니다. line-seq를 사용하는 것이 더 자연스러워 보입니다. 시퀀스에서 값을 합산하는 데 사용되는 것을 줄이는 것만 보았거나 비슷한 것이므로 다른 컬렉션을 만드는 데 사용하는 것이 흥미 롭습니다. – rifboy

+0

'(into # {} ...) 대신'set' 함수를 사용할 수 있습니다. – Jonas

0

난 항상 slurpre-seq와 그 분할 후 읽기 때문에 내 요구에 : 데이브 레이는 열려있는 파일을 유출하는 것이이 작업을 수행하는 것이 좋습니다 핸들을 피하기 위해 권리입니다.

관련 문제