From a a sequence, I need to fetch all the positions of the occurrence of a given item.
I'm asking myself if this is a good way to solve the problem:
(defn get-positions [item coll]
(->> (map-indexed vector coll)
(filter (fn [[_ v]] (= item v)))
(map first)))
This also works for strings, they'll be transformed to a sequence by the first map. However, if I know the input's are strings, would there be a more string specific approach for this problem?
Since you already have a general solution to the problem, why would you want to spend more effort to try to come up with a more specific one? The benefits of doing so here are negligible.
Just for variety's sake, here's another way to implement your function:
(defn positions [x coll]
(keep-indexed #(when (= x %2) %1) coll))
Related
I am new to clojure programming and would like some help with some code. I have this vector of vectors like below,
(def start-pos [[[:fox :goose :corn :you] [:boat] []]])
I would like to loop through the vector and remove an element from one of the internal vectors, e.g. remove ':goose' from start-pos.
I tried the code below but for some reason it doesnt work as intended,
(map #(disj (set %) :goose) start-pos)
Instead the result is,
(#{[:boat] [] [:fox :goose :corn :you]})
As you can see from the result, the internal vectors are now a set and yes, the original order is distorted, is there a way of removing the element and not disarrange the original order of the vectors, maybe without converting it to a set first? I choose this conversion to a set first because according to the docs disj only works for sets.
Add: This post is not similar to this suggested post as my vector is nested three vectors deep.
the internal vectors are now a set
That's because the result of #(disj (set %) :goose) returns a set.
original order is distorted
Sets don't preserve insertion order by default, similar to maps with over 8 keys.
I would like to loop through the vector and remove an element from one of the internal vectors, e.g. remove ':goose' from start-pos.
The function you need for removing an element from a collection by predicate is called remove, but...
The value you want to remove is actually nested three vectors deep in start-pos, so you'd need an additional iteration for each inner vector, and so on if you wanted to remove the keyword :goose from every vector recursively. That's an excuse to use clojure.walk:
(clojure.walk/postwalk
(fn [v]
(if (coll? v)
(into (empty v) (remove #{:goose}) v)
v))
start-pos)
=> [[[:fox :corn :you] [:boat] []]]
This walks every value in start-pos, removing :goose from any collections it finds.
Here is a less flexible approach, that I made more so for my own benefit (learning Clojure)
(update-in
start-pos
[0 0]
#(vec (concat
(subvec % 0 1)
(subvec % (inc 1)))))
It manually navigates in and reconstructs the :goose level of keywords to not have :goose inside
I think some alternative approaches to this problem include Specter and Zippers
you could also employ clojure zipper for that:
user> (require '[clojure.zip :as z])
user> (loop [curr (z/vector-zip start-pos)]
(cond (z/end? curr) (z/root curr)
(= :goose (z/node curr)) (recur (z/remove curr))
:else (recur (z/next curr))))
;; => [[[:fox :corn :you] [:boat] []]]
also, that is quite easy to do with clojure's core functions only:
user> (defn remv [pred data]
(if (vector? data)
(mapv (partial remv pred) (remove pred data))
data))
#'user/remv
user> (remv #{:goose} start-pos)
;; => [[[:fox :corn :you] [:boat] []]]
I'd like to do vector creation inside a function.
(map #([first %]) coll_of_tuples)
This gives the error
ArityException Wrong number of args (0) passed to: PersistentVector
clojure.lang.AFn.throwArity (AFn.java:429)
Any workaround besides using list? I'm looking for short notation.
If you want a shorter version there is a few options:
(map #(-> [(first %)]) coll)
(map #(do [(first %)]) coll)
(map (juxt first) coll)
I like peter's answer in the comments of
(map #(vector (first %)) coll_of_tuples)
Or alternately
(map #(-> % first vector) coll_of_tuples)
Or leaning on FP more and anon fn less:
(map (comp vector first) coll_of_tuples)
If you instead prefer to think of this as extracting the first 1-length sequence from each, this is a seq-ier answer:
(map #(take 1 %) coll_of_tuples)
If I needed the vector type I'd use (map #(vector (first %)) coll_of_tuples) as suggested by peter. So far it appears that list is the shortest notation.
You could also use for, which is very similar to map except for giving a symbolic name to each element of the sequence in turn:
(for [tuple coll_of_tuples]
[(first tuple)])
This is not quite as minimal as some of the other solutions, but in some instances it is nice to have a named symbol like tuple instead of %.
I have a vector of maps like this one
(def map1
[{:name "name1"
:field "xxx"}
{:name "name2"
:requires {"element1" 1}}
{:name "name3"
:consumes {"element2" 1 "element3" 4}}])
I'm trying to define a functions that takes in a map like {"element1" 1 "element3" 6} (ie: with n fields, or {}) and fiters the maps in map1, returning only the ones that either have no requires and consumes, or have a lower number associated to them than the one associated with that key in the provided map (if the provided map doesn't have any key like that, it's not returned)
but I'm failing to grasp how to approach the maps recursive loop and filtering
(defn getV [node nodes]
(defn filterType [type nodes]
(filter (fn [x] (if (contains? x type)
false ; filter for key values here
true)) nodes))
(filterType :requires (filterType :consumes nodes)))
There's two ways to look at problems like this: from the outside in or from the inside out. Naming things carefully can really help when working with nested structures. For example, calling a vector of maps map1 may be adding to the confusion.
Starting from the outside, you need a predicate function for filtering the list. This function will take a map as a parameter and will be used by a filter function.
(defn comparisons [m]
...)
(filter comparisons map1)
I'm not sure I understand the comparisons precisely, but there seems to be at least two flavors. The first is looking for maps that do not have :requires or :consumes keys.
(defn no-requires-or-consumes [m]
...)
(defn all-keys-higher-than-values [m]
...)
(defn comparisons [m]
(some #(% m) [no-requires-or-consumes all-keys-higher-than-values]))
Then it's a matter of defining the individual comparison functions
(defn no-requires-or-consumes [m]
(and (not (:requires m)) (not (:consumes m))))
The second is more complicated. It operates on one or two inner maps but the behaviour is the same in both cases so the real implementation can be pushed down another level.
(defn all-keys-higher-than-values [m]
(every? keys-higher-than-values [(:requires m) (:consumes m)]))
The crux of the comparison is looking at the number in the key part of the map vs the value. Pushing the details down a level gives:
(defn keys-higher-than-values [m]
(every? #(>= (number-from-key %) (get m %)) (keys m)))
Note: I chose >= here so that the second entry in the sample data will pass.
That leaves only pulling the number of of key string. how to do that can be found at In Clojure how can I convert a String to a number?
(defn number-from-key [s]
(read-string (re-find #"\d+" s)))
Stringing all these together and running against the example data returns the first and second entries.
Putting everything together:
(defn no-requires-or-consumes [m]
(and (not (:requires m)) (not (:consumes m))))
(defn number-from-key [s]
(read-string (re-find #"\d+" s)))
(defn all-keys-higher-than-values [m]
(every? keys-higher-than-values [(:requires m) (:consumes m)]))
(defn keys-higher-than-values [m]
(every? #(>= (number-from-key %) (get m %)) (keys m)))
(defn comparisons [m]
(some #(% m) [no-requires-or-consumes all-keys-higher-than-values]))
(filter comparisons map1)
Given the following data structure, I want to ask for "services-list" (a component) and receive back "entity-list" (a style).
(def style->components {"entity-list" ["services-list" "employee-list" "clients-list"]})
My solution is not so elegant:
(defn get-style-name [comp-name]
(-> (filter (fn [map-entry]
(let [v (val map-entry)
found-comp (some #(= % comp-name) v)]
found-comp
)) style->components)
first
first))
Is there a better way? Perhaps my problem started with the way I structured the data.
you can make it shorter and more clojurish this way:
(defn get-style-name [comp-name]
(ffirst (filter (fn [[_ v]]
(some #{comp-name} v))
component->style)))
there is a function ffirst, that works exactly like (first (first %))
using a destructuring in the filter function signature, you can retrieve the value of the map entry, avoiding unneeded let
instead of this function in some: #(= % comp-name) it is quite common to use the set: #{comp-name}
then you can use some instead of filter, as it returns the first logical true value returned by function, so you can remove ffirst:
(defn get-style-name [comp-name]
(some (fn [[k v]]
(when (some #{comp-name} v) k))
component->style))
also, if you change your data structure to use set instead of vector, you can make it even shorter:
(def component->style {"entity-list" #{"services-list"
"employee-list"
"clients-list"}})
(defn get-style-name [comp-name]
(some (fn [[k v]] (when (v comp-name) k))
component->style))
Just to add another alternative, nested sequence operations usually lend themselves to replacement with for:
(defn get-style-name
[comp-name]
(first
(for [[style-name comp-names] style->components
comp-name' comp-names
:when (= comp-name comp-name')]
style-name)))
Still, I'd prefer a solution where the mapping of component name to style name is pre-computed, e.g.
(def get-style-name
(->> (for [[style-name comp-names] style->components
comp-name comp-names]
[comp-name style-name])
(into {})))
This way, you avoid traversing the style->components map on every lookup.
(This is a question regarding style. I am aware this can be done with a bunch of conditionals, multimethods, etc.)
In the following function, null-vector is defined on each implementation. How can I set it once for the entire function? In general, is it possible to set a common binding to all implementations?
A closure won't work, since it null-vector needs an "argument", but I suppose I could partial it. However, that would still need computation of the size parameter. I'd like to avoid repeating code, obviously.
(defn path
"Returns a lazy sequence of vectors representing a monotonic path
walked over coll in n-dimensional space, where n is the cardinality
of coll's alphabet."
([coll]
(let [alphabet (set coll)
cardinality (count alphabet)
alpha-map (apply hash-map (interleave alphabet (range cardinality)))
null-vector (vec (repeat cardinality 0))]
(path coll null-vector alpha-map)))
([coll alpha-map]
(let [null-vector (vec (repeat (count (keys alpha-map)) 0))]
(path coll null-vector alpha-map)))
([coll origin alpha-map]
(let [null-vector (vec (repeat (count origin) 0))
unit-vector #(assoc null-vector (alpha-map %) 1)
sum-vectors #(vec (map + %1 %2))]
(reductions sum-vectors origin (map unit-vector coll)))))
I would create a "private" helper function:
(defn- null-copy-vector [coll]
(vec (repeat (count coll) 0)))
and then just call it in each branch of the function:
(defn path
"Returns a lazy sequence of vectors representing a monotonic path
walked over coll in n-dimensional space, where n is the cardinality
of coll's alphabet."
([coll]
(let [alphabet (set coll)
alpha-map (zipmap alphabet (iterate inc 0)) ;; note 1
null-vector (null-copy-vector alphabet)]
(path coll null-vector alpha-map null-vector)))
([coll alpha-map]
(let [null-vector (null-copy-vector alpha-map)] ;; note 2
(path coll null-vector alpha-map null-vector)))
([coll origin alpha-map]
(path coll origin alpha-map (null-copy-vector origin)))
([coll origin alpha-map null-vector]
(let [unit-vector #(assoc null-vector (alpha-map %) 1)
sum-vectors #(vec (map + %1 %2))]
(reductions sum-vectors origin (map unit-vector coll)))))
It may be this isn't satisfying to you because null-copy-vector isn't "inside" the overall function here, but I think this is pretty idiomatic. On a function that did not take multiple arities, I might use letfn to separate out an "internal" function but that won't work here.
Breaking things up like this also lets you a) reuse the basic building block functions elsewhere and b) lets you test in smaller chunks. You might want to skip the defn- and just use defn to make testing easier (although it is possible to test defn- with a bit more work).
I also broke out a new 4-arg form that takes the null-vector as the last arg, letting you pass it in directly if you know it so that you can avoid re-creating it from an already null vector. If you wanted to hide that 4-arg form, you could pull it into a separate defn- helper function.
Unrelated notes:
I modified your first branch to a simpler (imho) impl using zipmap and an infinite sequence.
Instead of (count (keys map)), just doing (count map) is sufficient (the count here is inside your helper function).