I know that if I define team as:
(def team ["A" "B" "C" "D"])
I can change the value "B" to "E" by
(assoc team 1 "E") > ["A" "E" "C" "D"]
If I now have:
(def teams '(["A" "B" "C"] ["D" "E" "F"] ["G" "H" "I"]))
How would I change "B" to "1" for example
I thought you might have to use assoc-in but that doesn't seem to be working or maybe I made a mistake. I tried
(assoc-in teams [0 1] "1")
You almost had it. You are using a list, when you should be using a vector, to do what you want to do:
(def teams [["A" "B" "C"] ["D" "E" "F"] ["G" "H" "I"]])
The reason for this is that a vector is an associative structure (i.e., it is a structure with key/value pairs). It's like a map, which is associative, except that for a vector, the key is the index in the vector. Contrast this with a list, which cannot be indexed into, and must be iterated to obtain an element. So, to use assoc-in, you need to use an associative structure, and a list won't do.
The error you got was: clojure.lang.PersistentList cannot be cast to clojure.lang.Associative, and a look at the source shows this:
IPersistentList gives:
public interface IPersistentList extends Sequential, IPersistentStack
Contrast with the Associative IPersistentVector:
public interface IPersistentVector extends Associative, Sequential, ...
Related
I am very new to clojure so this may have a simple fix. I have two examples of code that I can't seem to find the difference in why one works and the other doesn't. The first is:
(defn example []
(def demokeys (hash-map "z" 1 "b" 2 "a" 3))
(println demokeys)
(println (get demokeys "b")))
(example)
which is from https://www.tutorialspoint.com/clojure/clojure_maps_get.htm. This works the way I expect it to, with it printing the hash map and then a 2 on the next line.
The second example is:
(defn bill-total [bill]
(println bill)
(println (get bill "b"))
(println "sometext")
)
(bill-total[(hash-map "z" 1 "b" 2 "a" 3)])
which prints the hashmap, then nil, then sometext. Why does it not correctly print the 2 as it does in the previous example?
First of all, don't use def within defn unless you need dynamic runtime declarations (and even then, you should probably reconsider). Instead, use let for local bindings.
As to your main question, you have wrapped the map in a vector, with those [] here: (bill-total [...]). When calling a function, you don't need to repeat its arguments vector's brackets - call it just like you call println or hash-map, because they're also just regular functions.
So in the end, it should be (bill-total (hash-map "z" 1 "b" 2 "a" 3)).
As a final note, there's rarely a need to explicitly use hash-map, especially when you already know the keys and values. So, instead of (hash-map ...) you can use the map literal and write {...}, just like in {"z" 1, "b" 2, "a" 3} (I used commas here just for readability since Clojure ignores them).
Sincere apologies if this has been answered before. The search terms I came up with for this one weren't really specific...
I have defined the following function in a utils namespace, but it seems rather silly and is probably defined somewhere else:
(defn index-with
"returns a map of x -> (f x) for every x in xs"
[f xs]
(apply hash-map (mapcat #(vector % (f %)) xs)))
Here's an example of its usage:
(index-with count ["a" "bb" "ccc" "ddd"])
=> {"a" 1, "bb" 2, "ccc" 3, "ddd" 3}
If you were to invert the roles of keys and values (potentially ambiguous), you'd get something like group-by's output:
(group-by count ["a" "bb" "ccc" "ddd"])
=> {1: ["a"], 2: ["bb"], 3: ["ccc", "ddd"]}
I also looked at clojure.set/index but it seems to only cover a specific scenario (which doesn't apply here).
Does something like this exist already in the Clojure core-lib?
It seems like clojure.core/zipmap is reasonably close to what I am looking for:
(def xs ["a" "bb" "ccc" "ddd"])
(zipmap xs (map count xs))
=> {"a" 1, "bb" 2, "ccc" 3, "ddd" 3}
You have proposed two one line implementations. A third might be:
(into {} (map (juxt identity count)) xs)
All three of solutions appear to assume uniqueness in the xs input. If you have a seperate function then I'd expect it should deal with the collisions in a reasonable way.
If you are looking to accumulate a look-aside table of a pure function, then the function you want is memoize.
The memoized version of the function keeps a cache of the mapping from
arguments to results ...
I want to write a schema where an element e in a data structure can be any member in a set S of items; e ∈ S. With Clojure Spec this is expressed with a set like:
(spec/def ::key-set #{:subprocess :leiningen :nrepl})
(gen/sample (spec/gen ::key-set))
; => (:nrepl :subprocess :subprocess :leiningen :subprocess :nrepl :subprocess :leiningen :nrepl :subprocess)
for a set of keywords.
In Schema however a set is used to denote a set of things rather than one element member of a set. So how do I in Schema express that I want one member out of a set?
schema.core/enum is what you're looking for.
user=> (schema.core/validate (schema.core/enum "a" "b" "c") "a")
"a"
=> (schema.core/validate (schema.core/enum "a" "b" "c") "z")
clojure.lang.ExceptionInfo: Value does not match schema: (not (#{"a" "b" "c"} "z"))
I want to create a rdd such that each row has an index. I tried the following
Given an rdd:
["a" "b" "c"]
(defn make-row-index [input]
(let [{:keys [col]} input]
(swap! #rdd assoc :rdd (-> (:rdd xctx)
(f/map #(vector %1 %2 ) (range))))))
Desired output:
(["a" 0] ["b" 1] ["c" 2])
I got an arity error, since f/map is used as (f/map rdd fn)
Wanted to use zipWithUniqueId() in apache spark but I'm lost on how to implement this and I cant find equivalent function in flambo. Any suggestion and help is appreciated.
Apache-spark zip with Index
Map implementation in flambo
Thanks
You can simply call zipWithIndex followed by map using untuple:
(def rdd (f/parallelize sc ["a" "b" "c"]))
(f/map (.zipWithIndex rdd) f/untuple)
You can use .zipWithUniqueId exactly the same way but result will be different from what you expect. zipWithUniqueId will generate pairs but index field won't be ordered.
It should be also possible to use zip with, but as far as I can tell it doesn't work with infinite range.
(def idx (f/parallelize sc (range (f/count rdd))))
(f/map (.zip rdd idx) f/untuple)
Whenever you use zip you should be careful though Generally speaking RDD should be considered as an unordered collection if there is a shuffling involved.
Not sure how to phrase the question, but, I'm just playing around with the twitter api and clojure as a part of my wanting to learn clojure.
I am not sure what the clojure way of approaching this problem
I am trying to get first 5 tweets of all my followers. I can get the list of followers with the api, and I have a list of follower screen_name. Now, I have a function to get latest 5 tweets from a user. In C#, I would just declare a List<object> and add tweets to it inside a for loop. Clojure doesn't quite work that way.. so here's what I'm trying to do:
(defn get-tweets
[follower]
{:text (str "I am " follower)
:favs 0})
(defn get-all-followers-tweets
[]
(let [followers ["a" "b" "c"]
followers-tweets (map #(get-tweets %) followers)]
followers-tweets))
These are just mockups, but, you get the idea. Now, twitter returns something like this: [{:text "ssd" :fav 1} {:text "fed" :fav 2}]
so when I call get-all-followers-tweets, I get this:
(({:text "I am a", :favs 0}
{:text "I am b", :favs 0}
{:text "I am c", :favs 0}))
I don't know why the data is in 2 brackets, and I'm guessing it has something to do with map but, I just need the :text property from all collections.
doing (get response :text) or (get-in response [:text]) returns nil (assume response is the collection)
So, How do I get all the :text from the collection? Am I approaching this right? I tried (doseq [f followers] (get-tweets f)) and for but they seem very unnatural for getting just all the tweets.
What's the ideal clojure way of doing this?
Your get-tweets fn is returning a series of multiple maps, as a vector. You are then mapping that function over your followers, producing a sequence of sequences of maps. That's why there are two brackets - the outer sequence corresponds to the list of followers and each inner sequence is all the tweets from one follower grouped together.
I think the simplest approach if you're fine with discarding the identity of the authors is to use flatten, a function for unravelling nested sequential data structures to get just the items. That will give you just a sequence of maps without any grouping. You can then map :text over them to get just the texts.
e.g.
(defn get-all-followers-tweets
[]
(let [followers ["a" "b" "c"]
followers-tweets (map get-tweets followers)]
(flatten followers-tweets)))
(map :text (get-all-followers-tweets))
Maybe a more general solution is to consider mapcat, which stands for map-then-concat. It's the go-to approach when you have
a series of data items with some sort of internal structure.
that you want to "unpack" so that each produces one or more of the items you actually want.
It does this by mapping the given function over the outer items to produce a bunch of sequences and then concatenates all those sequences into one. But in this case our "unpacking function" is itself map so I don't think this approach is necessarily clearer here. That just makes it a little difficult to keep the different levels in mind:
(mapcat (partial map :text) (get-all-followers-tweets))