2012-07-15 9 views
6

Estoy escribiendo un fragmento de código que debe leerse en un archivo de texto que contiene datos. El archivo de texto tiene el formato:¿Cómo se lee un archivo con datos de prueba con Clojure?

name 1 4 
name 2 4 5 
name 3 1 9 

Estoy tratando de crear un vector de un mapa en forma [:name Sarah :weight 1 cost :4].

Cuando intento leer el archivo con el lector de línea, lee cada línea como un elemento para que la partición no sea correcta. Ver la respuesta a continuación:

(let [file-text (line-seq (reader "C://Drugs/myproject/src/myproject/data.txt")) 
         new-test-items (vec (map #(apply struct item %) (partition 3 file-text)))] 
    (println file-text) 
    (println new-test-items)) 


(sarah 1 1 jason 4 5 nila 3 2 jonas 5 6 judy 8 15 denny 9 14 lis 2 2 ) 
[{:name sarah 1 1, :weight jason 4 5, :value nila 3 2 } {:name jonas 5 6, :weight judy 8 15, :value denny 9 14}] 

Intenté simplemente tomar 1 partición, pero aún así la estructura no es correcta.

=> (let [file-text (line-seq (reader "C://Drugs/myproject/src/myproject/data.txt")) 
           new-test-items (vec (map #(apply struct item %) (partition 1 file-text)))] 
       (println file-text) 
       (println new-test-items)) 
(sarah 1 1 jason 4 5 nila 3 2 jonas 5 6 judy 8 15 denny 9 14 lis 2 2 ) 
[{:name sarah 1 1, :weight nil, :value nil} {:name jason 4 5, :weight nil, :value nil} {:name nila 3 2 , :weight nil, :value nil} {:name jonas 5 6, :weight nil, :value nil} {:name judy 8 15, :weight nil, :value nil} {:name denny 9 14, :weight nil, :value nil} {:name lis 2 2, :weight nil, :value nil} {:name , :weight nil, :value nil}] 
nil 

siguiente que trató de sorber el archivo, pero que es peor:

=> (let [slurp-input (slurp "C://Drugs/myproject/src/myproject/data.txt") 
      part-items (partition 3 slurp-input) 
      mapping (vec (map #(apply struct item %) part-items))] 
      (println slurp-input) 
      (println part-items) 
      (println mapping)) 
sarah 1 1 
jason 4 5 
nila 3 2 
jonas 5 6 
judy 8 15 
denny 9 14 
lis 2 2 

((s a r) (a h ) (1 1) (

por favor ayuda! Esto parece algo tan fácil de hacer en Java, pero me está matando en Clojure.

Respuesta

6

dividirlo en una secuencia de líneas:

(line-seq (reader "/tmp/data")) 

dividida cada una de ellas en una secuencia de palabras

(map #(split % #" ") data) 

hacer una función que toma un vector de datos uno y lo convierte en una mapa con las teclas correctas

(fn [[name weight cost]] 
    (hash-map :name name 
      :weight (Integer/parseInt weight) 
      :cost (Integer/parseInt cost))) 

continuación nido de nuevo juntos

(map (fn [[name weight cost]] 
     (hash-map :name name 
       :weight (Integer/parseInt weight) 
       :cost (Integer/parseInt cost))) 
    (map #(split % #" ") (line-seq (reader "/tmp/data")))) 

({:weight 1, :name "name", :cost 4} 
{:weight 2, :name "name", :cost 4} 
{:weight 3, :name "name", :cost 1}) 

también se puede hacer esto más compacta mediante el uso de zip-map

+1

porque este es perezoso, le toca a usted para recordar para cerrar el archivo cuando no se va a leer más datos de él. (A menudo encuentro mis secuencias de autoenvoltura en un lector perezoso cercano al vacío. –

+0

split viene de clojure.string y el lector viene de clojure.java.io –

+0

Arthur muchas gracias! Estaba perdido en esto. Probé tu solución, pero obtengo el siguiente error. => (mapa (fn [[nombre peso costo]] (hash-map: nombre nombre : peso (Entero/peso parseInt) : costo (costo entero/parseInt))) (número de mapa (split% # "") (línea-seq (lector "C: //Drugs/myproject/src/myproject/data.txt")))) CompilerException java.lang.RuntimeException: no se puede resolver el símbolo : dividir en este contexto, compilando: (NO_SOURCE_PATH: 5) – user1525748

3

Usted está tratando de hacer todo en un solo lugar sin probar los resultados intermedios. En su lugar, Clojure recomienda descomponer la tarea en varias subtareas, lo que hace que el código sea mucho más flexible y que se puede probar. Aquí está el código para su tarea (supongo que los registros en el archivo describen personas):

(defn read-lines [filename] 
    (with-open [rdr (clojure.java.io/reader filename)] 
    (doall (line-seq rdr)))) 

(defn make-person [s] 
    (reduce conj (map hash-map [:name :weight :value] (.split s " ")))) 

(map make-person (read-lines "/path/to/file")) 
Cuestiones relacionadas