title: Clojure: Idiomatic way of merge map's keys based on keys' similarity?
body: <p>I'm trying to merge a map's keys based the key value's similarity to produce a new map with the key values similar merged into one. The following is my code to illustrate my ideas:</p>
  
  <p>Given a dataset:</p>
  
  <pre><code>(def engineer-visits (incanter.core/dataset ["Engineer" "Credit" "Comments"]
                                [
                                 ["Jonah" 1 "OK"]
                                 ["Jonah" 2 "Very good"]
                                 ["Joneh" 0 "Not very good"]
                                 ["Joneh" 3 "Excellent"]
                                 ["Esther" 2 "Missing comment"]
                                 ["Esther" 4 "Extraordinary"]
  
                                 ]
                                ))
  </code></pre>
  
  <p>with value:</p>
  
  <pre><code>| Engineer | Credit |        Comments |
  |----------+--------+-----------------|
  |    Jonah |      1 |              OK |
  |    Jonah |      2 |       Very good |
  |    Joneh |      0 |   Not very good |
  |    Joneh |      3 |       Excellent |
  |   Esther |      2 | Missing comment |
  |   Esther |      4 |   Extraordinary |
  </code></pre>
  
  <p>The following produces a map from engineer to his/her records:</p>
  
  <pre><code>(def by-engineers (incanter.core/$group-by "Engineer" engineer-visits ))
  </code></pre>
  
  <p>with value:</p>
  
  <pre><code>{{"Engineer" "Jonah"} 
  | Engineer | Credit |  Comments |
  |----------+--------+-----------|
  |    Jonah |      1 |        OK |
  |    Jonah |      2 | Very good |
  , {"Engineer" "Joneh"} 
  | Engineer | Credit |      Comments |
  |----------+--------+---------------|
  |    Joneh |      0 | Not very good |
  |    Joneh |      3 |     Excellent |
  , {"Engineer" "Esther"} 
  | Engineer | Credit |        Comments |
  |----------+--------+-----------------|
  |   Esther |      2 | Missing comment |
  |   Esther |      4 |   Extraordinary |
  }
  </code></pre>
  
  <p>With the following function, I'd like to get:</p>
  
  <pre><code>(map-merged-by-key-value-similarity by-engineers 0.8)
  
  {{"Engineer" "Jonah"} 
  | Engineer | Credit |      Comments |
  |----------+--------+---------------|
  |    Jonah |      1 |            OK |
  |    Jonah |      2 |     Very good |
  |    Joneh |      0 | Not very good |
  |    Joneh |      3 |     Excellent |
  , {"Engineer" "Esther"} 
  | Engineer | Credit |        Comments |
  |----------+--------+-----------------|
  |   Esther |      2 | Missing comment |
  |   Esther |      4 |   Extraordinary |
  }
  
  
  (defn map-merged-by-key-value-similarity
        "From a map produced by $gorup-by on a datasest, produce a map of the same structure, with key column values merged by similarity."
        [a-map threshold]
        (let [
              column-keys (keys a-map)
              key-column-name (-&gt;&gt; column-keys
                                   first
                                   keys
                                   first)
              ;; Deconstruct the key column values from the key of the map, i.e. the pair of column name and column value:
              key-column-values (flatten (map vals column-keys)) 
              ;; Compute string clusters for the values:
              value-simularity-cluster (similarity-cluster key-column-values threshold)
              ;; Reconstruct the key for the updated map from the clustered column values:
              reconstructed-column-value-key-cluster-list (map (fn [cluster] 
                                                                 (map (fn [name] 
                                                                        {key-column-name name})
                                                                      cluster)) 
                                                               value-simularity-cluster)
              representative (fn [cluster] (first cluster)) ; out of a cluster
              map-from-cluster-combined-fn (fn [cluster] 
                                             ; the cluster is a list of maps from key-column-mane to string of the column's value
                                             (if (&lt; 1 (count cluster))
                                               ;; combine
                                               (apply merge-with conj-rows (map (fn [key] 
                                                                                       {(representative cluster) (a-map key)}) 
                                                                                     cluster))
                                               ;; as is
                                               {(first cluster) (a-map (first cluster))}
                                               ))
              ]
          (apply merge (map map-from-cluster-combined-fn reconstructed-column-value-key-cluster-list))
          )
        )
  </code></pre>
  
  <p>The above function indeed works as expected. I'd wish a more idiomatic way to achieve it. As there is a quite symmetry process of decomposing a map's key and value, processing on keys, and reconstructing back a similar map, I feel that it could be more eloquently done. I vaguely remember in Scala, some Mondard operator might be useful to access and process the information buried deep in a list structure. </p>
  
  <p>Thanks for your comment or help!</p>
  
  <p>Note: <code>similarity-cluster</code> converts a list of string into a list of list of strings, where similar strings are put into an enclosed list. It's my implementation. The details are not relevant to my question here. </p>