1
votes

I'm a Clojure noob. I'm trying to take a lazy sequence of maps and convert it into a single map. The map key is an integer and the value is a vector. I've seen lots of examples of merging maps e.g.

(merge map1 map2) ;;or
(into {} [{a: 1} {b: 2} {c: 3}])

but I'm still having difficulty when it's a lazy sequence. When I use:

(into {} mapSeq) 

it returns only the last map in the sequence.

(defn combine-maps [mapSeq]
  (pp/pprint (into {} mapSeq))))

(defn file-input-to-vec [file] 
  (let [page (line-seq (clojure.java.io/reader file))
        page-number (vec (mapv #(str/split %1 #" ") page))] 

    (combine-maps (for [i page-number]  
                { :pageID (edn/read-string (first i)) 
                  :outpages (convert-to-int-vec (drop 1 i)) }))))

I get the last page only:

{:pageID 6, :outpages [9770 0 8758 6103 9560 356 8469 3570 1178]}

I'd like this:

{:pageID 0, :outpages [6 5 2 4 1 3], 
 :pageID 1, :outpages [0 461 4772 1324 1735 487 5668],
 :pageID 2, :outpages [4412 0 209 3130 6902 8397 4373 905 3833],
 :pageID 3, :outpages [5103 1203 7063 0 5866 445 5498 6217 6498], 
 ... }
4

4 Answers

5
votes

The return value that you say you would like is not a legal map, because it has multiple occurrences of the key :pageID and multiple occurrences of the key :outpages. Clojure maps (and their corresponding things in most programming languages, e.g. dictionaries in Python) have at most one occurrence of each key.

If you update what you want as a return value to something that is a valid Clojure data structure, someone may be able to help with the code.

1
votes

if you haven't got a solution i'd like to recommend something. First of all i am a noob to clojure too but i think your solution wont work because of the multiple occurences of :pageId and :outpages as seen here docs.

If the key used in assoc already exists, the value is replaced

I'd recommend that instead of


(into {} [{:pageID 1 :outpages 2} 
       {:pageID 2 :outpages 3} 
      {:pageID 3 :outpages 4}])

you conjoin them to a vector of maps instead


(conj [] {:pageID 1 :outpages 2} 
       {:pageID 2 :outpages 3} 
      {:pageID 3 :outpages 4})

It'd fairly do any operation you need, for example to get :outpages at :pageId index


(nth [{:pageID 1, :outpages 2} {:pageID 2, :outpages 3} {:pageID 3, :outpages 4}] (- index 1))
1
votes

The solution is to remove :pageID and :outpages since they are the keys and values, respectively. Thanks for the input.

0
votes

If you have a list of vectors containing integers, like this

(def [[6 5 2 4 1 3], 
[0 461 4772 1324 1735 487 5668],
[4412 0 209 3130 6902 8397 4373 905 3833],
[5103 1203 7063 0 5866 445 5498 6217 6498]]

then you can get a map of page numbers to your vectors like this:

user> (into {} (map-indexed (fn [i page] [i page]) pages))
{0 [6 5 2 4 1 3],
 1 [0 461 4772 1324 1735 487 5668],
 2 [4412 0 209 3130 6902 8397 4373 905 3833],
 3 [5103 1203 7063 0 5866 445 5498 6217 6498]}

into knows how to make a map out of a list of two-item vectors.