I have a 2D vector that looks like this
(["2011-01-01" "2011" "01" "01"]
["1869-01-01" "1869" "01" "01"]
["1922-01-01" "1922" "01" "01"]
["1905-01-01" "1905" "01" "01"])
I want to have just a vector of just the second column so it will be like this
("2011" "1869" "1922" "1905")
What is the best way to do this in Clojure?
Be sure to always consult the Clojure CheatSheet for questions like this.
For something this simple, just use mapv (or map) and the second function:
(def data [["2011-01-01" "2011" "01" "01"]
["1869-01-01" "1869" "01" "01"]
["1922-01-01" "1922" "01" "01"]
["1905-01-01" "1905" "01" "01"]])
(mapv second data) => ["2011" "1869" "1922" "1905"]
I prefer mapv since it gives the result as a vector (non-lazy) which is easier to cut & paste w/o needing quotes.
If you have more complicated needs, you may wish to review the tupelo.array library. Your data is already in the form of a Clojure 2-D array (vector of vectors), so you can just use the col-get function:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[tupelo.array :as ta]))
(def data ...)
; Note zero-based indexing
(ta/col-get data 1) => ["2011" "1869" "1922" "1905"]
The library includes many other functions for input/output, get/set values, flip arrays up/down or left/right, rotation, adding/deleting rows & cols, etc. There is also a version that works with mutable arrays (Java native object arrays) instead of Clojure immutable data structures.
Possible answers
A. (reduce (fn [| [_ - ]] (conj | -)) [] data)
B. (map (fn [[_ - ]] -) data)
C. (map second data)
Related
I've been writing out a function in Clojure that would take a row of a 2d array and then multiples the values in it by a single value. I have the index to get the specific row and the value to multiply the row with in another array.
The function will return the array, that has now got values multipled by the single value.
Here's the code:
(def twod-array [[3.1 0.0023 0.35]
[0.21 0.00353 8.13]])
(def iandv [1 3.1])
(defn array-multiply [iandv twod-array]
(
let [array-row (nth twod-array (nth iandv 0))]
(map * [array-row] [(nth iandv 1)])
)
The let gets the array row and then it will return the row with the values inside multiplied with the value of the "index and value" array.
This has the closest I've gotten using the examples with the clojure.doc website and I'm getting a ClassCastException of the following:
ClassCastException clojure.lang.PersistentVector cannot be cast to java.lang.Number clojure.lang.Numbers.multiply (Numbers.java:148)
I've been looking at map vector and other map functions but I haven't been able to find a good solution.
more clojurish way could look something like this:
(defn array-multiply [[row mul] twod-array]
(update twod-array row #(mapv (partial * mul) %)))
user> (array-multiply iandv twod-array)
;;=> [[3.1 0.0023 0.35] [0.651 0.010943000000000001 25.203000000000003]]
Your code is somewhat hard to read, but basically, you're trying to multiply a number and a vector, that doesn't work.
(defn array-multiply [iandv twod-array]
(let [array-row (nth twod-array (nth iandv 0))]
(map * array-row [(nth iandv 1)])))
works since array-row already is a vector.
I'm trying to fill a Clojure vector with values from a map.
I have another vector of specific keys in the map the store the values I need.
I need to iterate the key-vec, get the values from the map and store them in another vector.
I've tried using loop+recur:
(let [keys-vec (:keys-vec item)
my-map (:my-map item)]
(loop [newV []
i 0]
(if (< i (count keys-vec))
(recur
(conj newV (get my-map (get keys-vec i)))
(inc i))
newV)))
And it worked.
But I know Clojure is known for it's minimalistic/efficient code writing style and I wanted to know whether there's a better way.
Any ideas?
I'd say, that the most idiomatic way will be to use original vector. I don't see any reason to explicitly clone an immutable datastructure.
You want the select-keys function to extract only the keys of interest from your map. See: http://clojuredocs.org/clojure.core/select-keys
Then, use the vals function to extract all of the values from the filtered map:
> (def my-map {:a 1 :b 2 :c 3})
> (def my-keys [:a :b])
> (select-keys my-map my-keys)
{:a 1, :b 2}
> (def filtered-map (select-keys my-map my-keys))
> filtered-map
{:a 1, :b 2}
> (vals filtered-map)
(1 2)
You should keep a browser tab open to the Clojure Cheatsheet at all times. It is invaluable for finding the functions you want. Keep studying it repeatedly, as you'll keep finding new things for years. This is my favorite version:
http://jafingerhut.github.io/cheatsheet/clojuredocs/cheatsheet-tiptip-cdocs-summary.html
Using Alan Thompson's example:
(def my-map {:a 1 :b 2 :c 3})
(def my-keys [:a :b])
... a simple and fast solution is
(mapv my-map my-keys)
;[1 2]
The alternative
(vals (select-keys my-map my-keys))
;(2 1)
... may not (and, in this case, does not) maintain the order given by my-keys.
This question already has answers here:
How do I create a primitive two-dimensional (2d) array of doubles in Clojure?
(2 answers)
Closed 6 years ago.
I have a 2D vector like
(def data [[1 1] [1 1]])
I would like to turn it into double[][].
i examined clojure.core and I tried :
1)
(->> (map double-array data)
(to-array-2d))
Unfortnately it returns Object[][] type of data, which fails in Java interop.
2)
(->> (map double-array data)
(double-array))
Of course it does not work because double-array expects a collection of numbers
3) I did not code it since it's heavy and I do not know if something esle exist but I could initialize a double[][] with (make-array Double/Type 2 2) [2 2 got by alen] and then fill it with loops.
Like in Java in fact.
4) A short way but a bit twisted
(def double-2d-array-type
(type (double-array [])))
(->> (map double-array data)
(into-array double-2d-array-type)))
Is there a direct way ? If it was possible to call directly double[] it would be better.
Like "(into-array double[] data)"
Just remove the first argument to into-array:
(into-array (map double-array data))
As long as there is at least one element in the input sequence, into-array can look at its type to guess the desired type of the output array. This guess isn't always what you want, because of inheritance, but for primitives it will never be wrong.
The Quest
Remove every substring in first-array for every string in second-array that matches.
What is the best way to do it in Clojure?
Example:
first-array: ["Adam" "Goolan" "silly"]
second-array: [ "a" "oo" "ll"]
result: ["Adm" "Gln" "siy"]
Note that the result should be the same if
second-array: [ "oo" "ll" "a"]
If it is by matched elements (i.e. first item in first matches first item in second and so on):
> (defn the-quest [xs ys]
(map #(clojure.string/replace (first %1) (second %1) "") (map vector xs ys)))
#'sandbox1427/the-quest
> (the-quest ["Adam" "Goolan" "silly"] ["a" "oo" "ll"])
("Adm" "Glan" "siy")
See #Lee's comment below:
> (map #(clojure.string/replace %1 %2 "") ["Adam" "Goolan" "silly"] ["a" "oo" "ll"])
("Adm" "Glan" "siy")
>
Note - the above courtesy of http://www.tryclj.com/
With any-to-any matching:
user=> (defn repl-all [x ys]
#_=> (reduce #(clojure.string/replace %1 %2 "") x ys))
user=> (defn the-quest [xs ys]
#_=> (map #(repl-all %1 ys) xs))
user=> (the-quest ["Adam" "Goolan" "silly"] ["a" "oo" "ll"])
("Adm" "Gln" "siy")
There's two slightly different formulations of the problem and your example doesn't quite indicate which you want:
Make one pass, removing any substring of the input strings which matches any of the second strings.
Make one pass for each string to remove in sequence. This can remove more characters than option 1, as each removal can create new substrings which otherwise wouldn't qualify.
If what you want is the second case, that seems to be taken care of. If it's the first case, I'd suggest something like
(import java.util.regex.Pattern)
(defn the-quest [strs to-remove]
(let[my-pattern (->> to-remove
(map #(Pattern/quote %))
(clojure.string/join "|")
re-pattern)]
(map #(clojure.string/replace % my-pattern "") strs)))
Here I just create a regular expression matching any of the to-remove strings and do one replace on instances of the regex. You have to bring in Pattern/quote if you want to be able to use regex control characters in the to-removes.
I'm trying to parse a nested array structure of the following form:
[element [[child1] [child2] [child3 [[subchild1] [subchild2]]]]]
I would also like to return a list with all symbols (and nothing else), regardless of nesting depth; however, I'm not looking for flatmap or flatten etc, since I need to perform more complicated additional work on every element.
This is what I came up with so far:
(defn create-element [rs element]
(if (symbol? element)
(cons element rs)
rs))
(defn parse
([rs element] (create-element rs element))
([rs element [children & more]] (if (nil? more)
(parse (parse rs element) (first children))
(parse (parse rs element) (first children) more))))
(defn n-parse [element]
(apply parse () element))
This works fine for the following input:
=> (n-parse ['bla [['asd] ['kkk] ['sss]]])
(sss kkk asd bla)
But this doesn't work:
=> (n-parse ['bla [['asd] ['kkk [['ooo]]] ['sss]]])
(sss kkk asd bla)
I'm still trying to wrap around my head around the types but can't seem to manage to get it right. For example, Haskell makes this easy with pattern matching etc, whereas Clojure doesn't allow same arity function overloading.
Also is there a more concise / idiomatic way (without having to resort to if?) I'd prefer pure Clojure solutions (no external libs) since this is actually for a Clojurescipt project.
Many thanks for any help!
I don't see whats wrong with flatten. If you want to do some work on the items first, do the work first and then flatten the result:
(defn map-tree
"Example: (map-tree + [1 2 [3 5]] [3 4 [5 6]])"
[f & trees]
(if (every? coll? trees)
(apply map (partial map-tree f) trees)
(apply f trees)))
(defmulti transformator identity)
;; transform 'sss element into something special
(defmethod transformator 'sss [_] "sss")
;; default transformation
(defmethod transformator :default [v] v)
Test:
user> (flatten (map-tree transformator '[bla [[asd] [kkk] [sss]]]))
(bla asd kkk "sss")
user>
Would that not work?