2012-08-16 16 views
7

से आलसी निकालें लाइनें मैं क्लोजर के साथ एक बड़ी (> 1 जीबी) फ़ाइल से अपनी लाइन संख्याओं द्वारा 5 लाइनों को पकड़ने की कोशिश कर रहा हूं। मैं लगभग वहां हूं लेकिन कुछ अजीब चीजें देख रहा हूं, और मैं समझना चाहता हूं कि क्या हो रहा है।बड़ी फ़ाइल

अब तक मुझे मिल गया है:

(defn multi-nth [values indices] 
    (map (partial nth values) indices)) 

(defn read-lines [file indices] 
    (with-open [rdr (clojure.java.io/reader file)] 
    (let [lines (line-seq rdr)] 
     (multi-nth lines indices)))) 

अब, (read-lines "my-file" [0]) एक समस्या के बिना काम करता है। हालांकि, [0 1] में गुजर मेरा पीछा स्टैकट्रेस देता है:

java.lang.RuntimeException: java.io.IOException: Stream closed 
     Util.java:165 clojure.lang.Util.runtimeException 
     LazySeq.java:51 clojure.lang.LazySeq.sval 
     LazySeq.java:60 clojure.lang.LazySeq.seq 
     Cons.java:39 clojure.lang.Cons.next 
      RT.java:769 clojure.lang.RT.nthFrom 
      RT.java:742 clojure.lang.RT.nth 
     core.clj:832 clojure.core/nth 
     AFn.java:163 clojure.lang.AFn.applyToHelper 
     AFn.java:151 clojure.lang.AFn.applyTo 
     core.clj:602 clojure.core/apply 
     core.clj:2341 clojure.core/partial[fn] 
     RestFn.java:408 clojure.lang.RestFn.invoke 
     core.clj:2430 clojure.core/map[fn] 

ऐसा लगता है कि इससे पहले कि मैं धारा फ़ाइल से दूसरी पंक्ति पढ़ सकते हैं बंद कर दिया जा रहा है। दिलचस्प बात यह है कि अगर मैं (nth lines 200) जैसे फ़ाइल से मैन्युअल रूप से एक लाइन खींचता हूं, तो multi-nth कॉल सभी मानों के लिए काम करता है < = 200.

कोई विचार क्या हो रहा है?

उत्तर

9

नक्शा (और लाइन-सीईसी) आलसी अनुक्रम लौटाता है, इसलिए फ़ाइल को बंद करने वाले खुले रिटर्न के साथ आपकी कॉल के समय तक कोई भी लाइन जरूरी नहीं पढ़ी जाती है।

(defn multi-nth [values indices] 
    (map (partial nth values) indices)) 

(defn read-lines [file indices] 
    (with-open [rdr (clojure.java.io/reader file)] 
    (let [lines (line-seq rdr)] 
     (doall (multi-nth lines indices))))) 

या कुछ इस तरह:

मूल रूप से, आप के साथ खुले रिटर्न, जिसके लिए आप DOALL उपयोग करने से पहले पूरे वापसी मान का एहसास करने की जरूरत है। ध्यान रखें कि निर्दिष्ट बहु पंक्तियों के लिए खोज करते समय आपकी बहु-पंक्ति रेखा सीक के सिर पर रखती है, जिसका अर्थ यह है कि यह सभी पंक्तियों को स्मृति में अंतिम निर्दिष्ट एक तक रखेगा - और इसका उपयोग करके इसका मतलब है प्रत्येक सूचकांक के लिए बार-बार लाइन-सीक के माध्यम से कदम उठा रहे हैं - आप इसे ठीक करना चाहेंगे।

अद्यतन:

ऐसा कुछ काम करेगा। यह मुझे पसंद से थोड़ा छोटा है लेकिन यह सिद्धांत दिखाता है, मुझे लगता है: ध्यान दें कि यहां सूचकांक सेट करने की आवश्यकता है।

(defn multi-nth [values indices] 
(keep 
    (fn [[number line]] 
    (if (contains? indices number) 
     line)) 
    (map-indexed vector values))) 

(multi-nth '(a b c d e) #{2 3}) 
    => c d 
+0

अच्छा बिंदु देखते हैं। क्या मुझे इसे सही करने के लिए निम्न-स्तरीय जावा यादृच्छिक एक्सेस विधि कॉल का उपयोग करने की आवश्यकता होगी? –

+0

मुझे लगता है कि आप मानचित्र-अनुक्रमित और फ़िल्टर का उपयोग करके कोड को स्पष्ट रूप से साफ़ कर सकते हैं। मैं एक मिनट में अपडेट करूंगा ... –

+0

आह ठीक है, यह बढ़िया है। यदि यह आपके इच्छित वाक्य से सिंथैक्टिक रूप से उलझन में है, तो आप फ़िल्टर-फ़ंक्शन को बनाए रखने और संभावित रूप से अनुक्रमित करने का उपयोग कर सकते हैं। अब इसमें देख रहे हैं ... –

5

with-file फ़ाइल बंद कर देता है एक बार अपने शरीर को मार डाला गया है। तो एक बार multi-nth निष्पादित किया गया है कि फ़ाइल बंद है, जिसका अर्थ है कि आप एक बंद फ़ाइल को इंगित करने वाले आलसी अनुक्रम के साथ समाप्त होते हैं।

(read-lines "my-file" [0]) काम करता है क्योंकि आलसी अनुक्रम का केवल पहला तत्व महसूस किया जाता है।

इस मुद्दे को ठीक करने के लिए, आप doall साथ अनुक्रम महसूस किया जा करने के लिए मजबूर करने की जरूरत है:

(defn multi-nth [values indices] 
    (doall (map (partial nth values) indices))) 

एक बहुत विस्तृत विवरण के लिए https://stackoverflow.com/a/10462159/151650

+0

आह। समझ में आता है। धन्यवाद! –

संबंधित मुद्दे