Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert map keys and values to string array

Tags:

clojure

How do I convert a clojure map into string, almost key value pair, as shown below:

Clojure data:

(def data { :starks "Winter is coming" :Lannisters "Hear me roar" })

I want to convert the above to

"starks" "winter is coming" "Lannisters" "hear me roar"

I don't want any identifiers / delimiters between but obviously "starks" should always be followed by "winter is coming"

I tried this:

(str (keys data) (vals data))

Which outputs this:

"(:starks :Lannisters)(\"Winter is coming\" \"Hear me roar\")"

Which is not what I want at all...

  • The map data keys and values are not always the same so it needs to be generic
  • there will always be just one level, as in, the value will not contain a nested map etc..

Edit

What I'm actually trying to do:

I am trying to index a few thousand Neo4j nodes with clojure. To help me with this task, I am using Neocons Clojure neo4j library.

According to the documentation, the add-to-index accepts properties and values like so:

(nn/add-to-index (:id node) (:name idx) "username" "joe")))

which is, in my above case, going to look like

(nn/add-to-index (:id node) (:name idx) "starks" "winter is coming" "Lannisters" "Hear me roar")))

now, I have my Node, I can access the node properties with (:data node) and that gives me a clojure map.

The property differs pretty much from node to node so I'm trying to figure out how to pass that map to the library in the way that it understands..

Marius Danila's answer got me almost there.

Doing

(map name (apply concat data))

still complains of the third parameter, as it has the braces around the result.

So, how can I achieve this? Do I just have to write a whole lot of if-not blocks to construct the properties myself?

Thanks

like image 957
LocustHorde Avatar asked Apr 15 '13 14:04

LocustHorde


4 Answers

This should do the trick:

(map name (apply concat data))

A map can be viewed as a sequence of key-value pairs, which in turn represented as arrays of 2 elements. We're concatenating the pairs and then we extract the name from the keywords and strings (for string this does nothing, for keywords it returns the bit without ':').

From the code you've posted, I'm guessing you would use this like so:

(apply nn/add-to-index (list* (:id node) (:name idx) (map name (apply concat data))))
like image 87
Marius Danila Avatar answered Sep 24 '22 14:09

Marius Danila


The (nn/add-to-index ...) function simply accepts only four arguments. The node, index and one key/value pair. So you have too loop through your data like.

(doseq [[k v] data]
  (nn/add-to-index (:id node) (:name idx) (name k) (clojure.string/lower-case v))))

Unlike the the str function in Clojure the add-to-index function is more limited and simply does not accept variable parameter lists.

like image 34
Niclas Meier Avatar answered Sep 25 '22 14:09

Niclas Meier


You can use vector to have array like random access:

=> (def v (vec (map name (apply concat data))))
=> (v 0)
;"starks"
=> (v 1)
;"Winter is coming"
like image 37
Grzegorz Luczywo Avatar answered Sep 24 '22 14:09

Grzegorz Luczywo


You could try the following:

=> (interleave (map name (keys data)) (vals data))

;; which returns ("starks" "Winter is coming" "Lannisters" "Hear me roar")
like image 22
user499049 Avatar answered Sep 24 '22 14:09

user499049