is there any way i can get the values of a Listbox in seesaw as a collection, that Clojure can handle?
The most i've got was a JList, which Clojure can't handle.
/edit: To Clarify: For Example i want to get all of the Elements of a Listbox and conj a new Element onto them. But Because the return value of the listbox is a JList, Clojure naturally can't do that.
I can't seem to find any method to extract all Elements from the listbox.
See this. You can use getModel method to get ListModel. And then use getElementAt and getSize method to build array or list or whatever you want.
(def data (into-array String ["one" "two" "three" "four"]))
(def myList (JList. data))
(->> myList
.getModel
((juxt identity (memfn getSize)))
((fn [[a b]] (map #(.getElementAt a %) (range b))))
(apply vector) (#(conj % "five")))
Related
I have a map where each key has a collection as value:
{:name ["Wut1" "Wut2"] :desc ["But1" "But2"]}
The value collections can be assumed to have the same number of elements.
How to transform it into a list (or vector) where each element is a map with key being the key from original collection and value being 1 value like:
[{:name "Wut1" :desc "But1"} {:name "Wut2" :desc "But2"}]
It should be said that the number of keys is not known before (so I can't hardcode for :name and :desc)
(fn [m]
(let [ks (keys m)]
(apply map (fn [& attrs]
(zipmap ks attrs))
(vals m))))
Get the list of keys to use to label everything with
Use apply map to "transpose" the list-of-lists in (vals m) from "for each attribute, a list of the values it should have" to "for each object, a list of the attributes it should have".
zipmap that back together with the keys extracted in the first part.
As a general rule apply map vector will always do a transpose operation:
(apply map vector '(["Wut1" "Wut2"] ["But1" "But2"]))
;;=> (["Wut1" "But1"] ["Wut2" "But2"])
With that one trick in hand, we just need to make sure to zipmap each vector object (e.g. ["Wut1" "But1"]) with the keys:
(fn [m]
(->> m
vals
(apply map vector)
(map #(zipmap (keys m) %))))
;;=> ({:name "Wut1", :desc "But1"} {:name "Wut2", :desc "But2"})
Another rule to go by is that there's a problem when you have consecutive maps - really you ought to bring together the map functions, rather than needlessly transferring items from list to list. (This can often be done using comp). See #amalloy's solution for how to avoid double mapping. Also of course the keys function call should not be done repeatedly as here.
How can I map a function over just the first elements of vectors in a list?
So I have
(["1" "sometexthere" ...]["2" "somemoretext" ...] ....)
I need to use read-string to convert the stringy numbers into ints (or longs).
If you want just the list of results, you can combine the function with first and map it, as #leetwinski recommended in the comments.
(map #(clojure.edn/read-string (first %)) items)
If you want to get back the structure you had, but with those particular elements mapped by the function, update and update-in are your friends:
(map #(update % 0 clojure.edn/read-string) items)
For more involved transformations you may also be interested in specter's transform.
You can use comp to compose functions:
(require '[clojure.edn :as edn])
(def items [["1" "sometexthere" ,,,] ["2" "somemoretext" ,,,] ,,,])
(map (comp edn/read-string first) items)
;=> (1 2 ,,,)
I like the comp solution by Elogent, however I think for readability I prefer the use of a threading macro:
(map #(-> % first clojure.edn/read-string) items)
To each his/her own, just my personal preference.
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
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))))
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.
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"
You could try the following:
=> (interleave (map name (keys data)) (vals data))
;; which returns ("starks" "Winter is coming" "Lannisters" "Hear me roar")
I have the following working code to convert a list with nested maps (actually tweet data) to a map:
(defn filter
"This function returns a map with the user as key, #followers as value"
[raw-tweets]
(let [users (map :user raw-tweets)
names (map :name users)
followers (map :followers_count users)]
(zipmap names followers)))
Although this works as expected, I was wondering if there would be a more idiomatic way to do this in Clojure. Any alternatives?
What you have is fine, though you can build the map as you go by using reduce:
(defn user-followers [raw-tweets]
(reduce #(assoc %1 (:name %2) (:followers_count %2))
{} (map :user raw-tweets)))
I'm only starting to learn clojure but I think this way might be a bit more idiomatic. It's an alternative in any case.
(defn filter
"This function returns a map with the user as key, #followers as value"
[raw-tweets]
(into {} (map #(let [user (:user %)]
[(:name user) (:followers_count user)])
raw-tweets)))
It maps over the raw tweets with a function that retrieves the user for each tweet and returns a vector with the name and followers count for that user. The into function takes two sequences and conjoins every element of the second one onto the first, which will turn the list of vectors into a map before it's returned from the filter function.
I find #Daan's answer nice, but I'd add destructuring into the mix.
(defn filter-tweets
"This function returns a map with the user as key, #followers as value"
[raw-tweets]
(into {} (map (fn [{{name :name follower-count :followers_count} :user}]
[name follower-count])
raw-tweets)))
I don't like the (map (fn ...)) pattern - it's really just an ugly way to write a for comprehension. I'd write this as:
(into {}
(for [{:keys [user]} raw-tweets]
((juxt :name :followers_count) user)))
Or this, which feels a little less natural to me but avoids inventing names for values you're just going to use once anyway.
(into {} (map (comp (juxt :name :followers_count) :user)
raw-tweets))
Here's the code :
(def entry {:name tempName :num tempNum})
(def tempList '(entry))
(println (get (nth tempList 0) (:name)))
Exception in thread "main" java.lang.IllegalArgumentException: Wrong number of args passed to keyword: :name
In this bit of code, I define a map called entry containing a :name and a :num, then I put it in a list, then I try to print the :name field of the first (and only) element of the list. (or at least this is what I think my code does :o)
I can access name from the entry map before I put it in the list, but once it's in the list I get this error. What args am I supposed to give ?
There are two problems.
First, for lists that contain symbols to be resolved (like the symbol entry in your case), you have to use syntax-quote (backtick) instead of regular quote (apostrophe); so this line:
(def tempList '(entry))
should be:
(def tempList `(entry))
or just (using a vector, which is more idiomatic and easier to use in Clojure):
(def tempList [entry]) ; no quoting needed for vectors
Then, change this line
(println (get (nth tempList 0) (:name)))
to either this:
(println (get (nth tempList 0) :name))
or this:
(println (:name (nth tempList 0)))
Using nth on a list is a bad idea because it has to do a linear search to retrieve your element, every time. Vectors are the right collection type to use here.
Vectors are "maps" of indices to values. If you use a vector instead of a list you can do this:
(:name (tempList 0))
Or:
(get (get tempList 0) :name)
Or:
(get-in tempList [0 :name]))
take the ( ) off from (:name) on the 3rd line.
:keywords are functions that take a map as an argument and "look themselves up" which is quite handy though it makes the error slightly more confusing in this case
(get (nth '({:name "asdf"}) 0) :name))
I would write your code like this:
(def entry {:name tempName :num tempNum})
(def tempList (list entry))
(println (:name (first tempList)))
Note that first is much neater than using nth, and keywords can act as functions to look themselves up in the map. Another equivalent approach is to compose the functions and apply them to the list:
((comp println :name first) tempList)