2013-03-10 1 views
0

"key1 $ value1, key2 $ value2"형식의 문자열을 map을 반환하는 clojure에 함수를 작성하고 싶습니다. 나는 이걸 생각해 냈다.이 클로저 함수가 목록을 반환하지 못하도록하는 방법

(defn get-map 
    "Returns a map of key value pairs from a string formatted in the form 'key1$value1,key2$value2'" 
    [line] 
    (let [result {}] 
    (for [item (split line #",")] 
     (let [pair (split item #"\$")] 
     (assoc result (nth pair 0) 
      (if (= (.size pair) 2) (nth pair 1) "")))))) 

이 코드의 유일한 문제는 목록 내에있는지도를 반환한다는 것입니다.

=>(get-map "key1$value1,key2,value2") 
({"key1" "value1"} {"key2" "value2"}) 

결과를 첫 번째 let 양식의 마지막 표현식으로 반환하려고했지만 그 결과는 빈지도입니다.

(defn get-map 
    "Returns a map of key value pairs from a string formatted in the form 'key1$value1,key2$value2'" 
    [line] 
    (let [result {}] 
    (for [item (split line #",")] 
     (let [pair (split item #"\$")] 
     (assoc result (nth pair 0) 
      (if (= (.size pair) 2) (nth pair 1) "")))) 
    result)) 

=>(get-map "key1$value1,key2,value2") 
{} 

두 질문 -

  1. 어떻게 목록 래퍼없이 단지지도를 반환하는 함수를 수정해야합니까?
  2. 왜 첫 번째 let 양식의 마지막 표현식으로 결과를 반환해도 빈지도가 반환 되었습니까?

더 나은, 더 관용적 인 방법으로 동일한 기능을 쓸 제안이 있으면 감사하겠습니다.

답변

2

for 그것이 지능형리스트의 루프가 아닙니다. 기본적으로 사용자의 컬렉션에있는 각 항목을 가져 와서 지정한 이름 (이 경우 item)에 바인딩 한 다음 이라는 표현 (이 경우 let [pair...)을 계산합니다. 각 평가 결과는 시퀀스로 반환됩니다. 예를 들어

:

(for [item (split "key1$value1,key2$value2" #",")] 
    item) 
;returns: ("key1$value1" "key2$value2") 

함수에서 실제로 목록을 만들어 for입니다. let으로 묶인 이름은 이 아니므로 for은 해당 표현식이 result 인 것으로 계산할 때마다 여전히 빈지도입니다. 그래서 하나의 항목이있는지도 목록을 얻게됩니다.

(for [item (split "key1$value1,key2$value2,key3" #",")] 
    (let [pair (split item #"\$")] 
    [(nth pair 0) (nth pair 1 "")])) 
;returns: (["key1" "value1"] ["key2" "value2"] ["key3" ""]) 

그런 다음 설정하는 into를 사용할 수 있습니다 여기에

은 $이없는 경우 기본을 제공하기 위해 nth 의-찾을 수없는 기능을 사용하는 키 - 값 쌍의 목록을 생성하는 방법 지도로 그. 다음은 완전한 기능입니다.

(defn get-map 
    "Returns a map of key value pairs from a string formatted in the form 'key1$value1,key2$value2'" 
    [line] 
    (into {} 
    (for [item (split line #",")] 
     (let [pair (split item #"\$")] 
     [(nth pair 0) (nth pair 1 "")])))) 
2
(defn get-map 
    "Returns a map of key value pairs from a string formatted in the form 'key1$value1,key2$value2'" 
    [line] 
    (->> (clojure.string/split line #",") 
     (mapcat #(clojure.string/split % #"\$")) 
     (apply hash-map))) 

user> (get-map "key1$value1,key2$value2") 
{"key1" "value1", "key2" "value2"} 

질문 1에 대한 답변/힌트 : 항상은 항상 시퀀스를 반환합니다. 그것은 Clojure에서 목록을 이해합니다.

질문 2에 대한 대답/힌트 : Clojure의 데이터 구조는 변경할 수 없습니다. 즉, 기존 맵을 사용하여 기존 맵을 변경하지 않고 새 맵을 리턴합니다.

2

for 양식은 지연 목록 이해가 없으므로 구조를 순차적으로 업데이트하는 데 적합하지 않습니다. for을 사용하여 페어 목록을 생성하고 reduce을 맵에 패키지화 할 수 있습니다. 또는 감소를 수행하는 into를 사용

(defn get-map [line] 
    (into {} 
    (for [item (split line #",")] 
     (split item #"\$")))) 

re-seq를 사용하여 또 다른 가능한 구현 : Clojure의에서

(defn get-map [s] 
    (into {} (map #(subvec % 1) (re-seq #"([^\$]+)\$([^,]+),*" s)))) 
관련 문제