I have a list of lists and a value. My goal is a new list of lists, where the value is conjed (new first item) to the first list matching a predicate (eg > to the first item of the list). If no list matches the predicate, I want my value to "begin" a new list at the end of lists.
if my list is: ['(2 3 4) '(4 5 6 7) '(5 6 7)]
and my value: 3
and my predicate: (comp (partial < my-value) first)
then my result should be: ['(2 3 4) '(3 4 5 6 7) '(5 6 7)]
if my value was: 10
my result should be: ['(2 3 4) '(4 5 6 7) '(5 6 7) '(10)]
This problem confuses me, because my imperative mind keeps telling me how easy it should be, but I cannot find an easy (ok, be honest: any) solution. this is my attempt so far:
(defn add-to-first-list-that-matches [func value]
(loop [result []
remaining-lists list-of-lists
value-to-add value]
(if (empty? remaining-lists)
result
(let [current-list (first remaining-lists)
value-matches? (func value-to-add current-list)
new-list (if value-matches? (conj value-to-add current-list) current-list)]
(recur (conj new-list result)
(rest remaining-lists)
(if-not value-matches? value-to-add nil))))))
(it crashes)
please enlighten me with some clojure expression magic :)
btw. I want to solve this as part of the longest-increasing-subsequence problem.
This uses loop-recur.
(defn add-to-ll
[ll pred value]
(loop [[current & unprocessed] ll
processed []]
(cond
(pred current) (concat processed
[(cons value current)]
unprocessed)
(empty? unprocessed) (concat processed
[current]
[[value]])
:else (recur unprocessed
(conj processed current)))))
(def l-l1 [[2 3 4] [4 5 6 7] [5 6 7]])
(add-to-ll l-l1 (comp (partial < 10) first) 10)
=> ([2 3 4] [4 5 6 7] [5 6 7] [10])
(add-to-ll l-l1 (comp (partial < 3) first) 3)
=> ([2 3 4] (3 4 5 6 7) [5 6 7])
You could also use split-with
(defn add-to-ll
[ll pred value]
(let [[first-lists [to-change & rest-lists]] (split-with (complement pred) ll)]
(if to-change
(concat first-lists [(cons value to-change)] rest-lists)
(concat ll [[value]]))))
Performance wise the first solution should run a bit faster.
Ye olde lazy-seq:
(defn add-to-first-match
[pred x coll]
(lazy-seq
(if-let [s (seq coll)]
(let [fst (first s)]
(if (pred fst)
(cons (conj fst x) (rest s))
(cons fst (add-to-first-match pred x (rest s)))))
(cons (list x) nil))))
Note: one could further extract list into an argument and allow for example also vector as element constructor.
(defn find-index
"find index of the first item in s matching predicate `pred`"
[pred s]
(first (keep-indexed (fn [index item]
(if (pred item)
index
nil))
s)))
(defn update-first-match
"update first item in s that matches `pred` using (f item args*)"
[s pred f & args]
(apply update-in s [(or (find-index pred s)
(count s))]
f args))
(def my-lists
['(2 3 4) '(4 5 6 7) '(5 6 7)])
(defn add-to-first-list-less-than
[l n]
(update-first-match l #(< n (first %)) conj n))
;; usage:
(update-first-match my-lists #(< 5 (first %)) conj 5)
;; or
(add-to-first-list-less-than my-lists 5)
Here is my attempt to answer more succinctly using reduce:
(defn add-to-first-list-that-matches
[value lists]
(let [pred (comp (partial < value) first)
[found result] (reduce (fn [[found result] el]
(if (and (not found) (pred el))
[true (conj result (cons value el))]
[found (conj result el)]))
[false []]
lists)]
(if found
result
(conj result (list value)))))
I am using the idiom of a vector in reduce to carry multiple values (a boolean to indicate whether a match has been found, plus the modified data structure we are building up). I was also able to combine the various conditions into a single if per element, plus a final post-condition rather than nested conditions or a multi branch cond.
Here is how it works with your examples:
user> (add-to-first-list-that-matches 3 ['(2 3 4) '(4 5 6 7) '(5 6 7)])
[(2 3 4) (3 4 5 6 7) (5 6 7)]
user> (add-to-first-list-that-matches 10 ['(2 3 4) '(4 5 6 7) '(5 6 7)])
[(2 3 4) (4 5 6 7) (5 6 7) (10)]
Related
I want to convert from a simple list:
'(1 2 3)
To a one dimensional array (vector):
#(1 2 3)
I found this question which is similar but does not cover this problem.
I also managed to find a way to achieve it. Not sure if it is the best:
CL-USER> (coerce '(1 2 3) 'vector)
#(1 2 3)
CL-USER> (type-of *)
(SIMPLE-VECTOR 3)
I wonder if it is possible to use make-array to achieve the same result. I tried:
CL-USER> (make-array '() :initial-contents '(1 2 3))
#0A(1 2 3)
CL-USER> (type-of *)
(SIMPLE-ARRAY T NIL)
This is close, but I do not understand #0A in #0A(1 2 3).
For some reason that I do not understand, this output does not work on further compositions, such as aref:
CL-USER> (aref #0A(1 2 3) 0)
; Evaluation aborted on #<SIMPLE-ERROR "Wrong number of subscripts, ~W, for array of rank ~W." {1003C07793}>.
Is it possible to use make-array to achieve the same result as coerce?
What are the differences between these two approaches?
Is one of them faster or more elegant than the other?
COERCE is fine, you can even specify the element-type if you want:
USER> (coerce '(1 2 3) '(vector fixnum))
#(1 2 3)
USER> (describe *)
#(1 2 3)
[simple specialized vector]
Element-type: FIXNUM
Length: 3
You can do the same with make-array, but you need to give the right dimension. The dimension parameter indicates how many rows, columns, etc. the possibly multi-dimensional array has. It should be a list, but when you only have one dimension, it can just be a number. Both forms here are equivalent:
USER> (make-array 3 :initial-contents '(1 2 3))
#(1 2 3)
USER> (make-array '(3) :initial-contents '(1 2 3))
#(1 2 3)
Usually you would call (length list). The added value compared to coerce is that you can specify the :fill-pointer or :adjustable arguments, something that the type argument of coerce cannot convey.
The printed representation of an array is #nA(), where n is the number of dimensions of the array, where the number and A is omitted if its a vector (n = 1). For example:
USER> (make-array '(10 2) :initial-element 0)
#2A((0 0) (0 0) (0 0) (0 0) (0 0) (0 0) (0 0) (0 0) (0 0) (0 0))
For a given array of dimension n, you access the elements with aref and as many arguments as there are dimensions, in row-major order (the same order you specified the dimensions in make-array).
USER> (aref * 5 1)
0 (0 bits, #x0, #o0, #b0)
In your example, you defined an array of dimension 0, because you wrote '() (a.k.a. just () or nil) as the dimension. This can be used if you need a box to store a single element:
USER> (defparameter *box* (make-array nil :element-type '(mod 8)))
*BOX*
USER> (describe *box*)
#0A0
[simple specialized array]
Element-type: (UNSIGNED-BYTE 4)
Dimensions: NIL
Storage vector: #<(SIMPLE-ARRAY (UNSIGNED-BYTE 4) (1)) {101EA0C59F}>
; No values
USER> (setf (aref *box*) 7)
7 (3 bits, #x7, #o7, #b111)
USER> (incf (aref *box*))
8 (4 bits, #x8, #o10, #b1000)
USER> (aref *box*)
8 (4 bits, #x8, #o10, #b1000)
(as you can see, the values that can be stored in the array are the ones corresponding to the upgraded-element-type, here (unsigned-byte 4); for example, (setf (aref *box*) (expt 2 16)) signals an error)
It looks like :initial-contents had the same result as :initial-element, because with your example the content of the zero-dimensional array was the list (1 2 3)
Is one of them faster or more elegant than the other?
I try to use coerce when possible because it's shorter to write and it looks more descriptive of what I am doing. I don't think it is faster, unless you know in advance the length of the list.
I want to apply the function (* x 2) to every other element in a list and return the entire list using the loop macro. The solution I've come up with so far is this:
(defun double-every-other (xs)
(loop for x in xs by #'cddr collect (* x 2)))
However, this will double every other element and only return the elements that were doubled, so if I executed:
(double-every-other '(1 2 3 4))
The result would be:
'(4 8)
But I want the result to be:
'(1 4 3 8)
Is there a way I can do this using (loop)?
Another version with less math:
(defun double-every-other (list)
(loop
for (a b) on list by #'cddr
collect a
when b collect (* b 2)))
(double-every-other '(1 2 3 4))
=> (1 4 3 8)
(double-every-other '(1 2 3 4 5))
=> (1 4 3 8 5)
Obviously, you won't be able to abstract the N as easily as the other answer (if you are thinking "macro", stop now). Here we iterate using the on keyword, which means each sublist is visited in turn. Since we use by #'cddr, every other sublist is skipped. The destructuring syntax (a b) binds the first and second elements of the visited list.
You can for instance test an integer increasing while the list is scanned:
(defun double-every-other (xs)
(loop for x in xs
for i from 1
if (oddp i)
collect x
else collect (* x 2)))
(defun double-every-other (xs)
(loop for x in xs
for doublep = nil then (not doublep)
collect (if doublep (* x 2) x)))
another version, without loop at all:
(defun make-cycled (&rest items)
(setf (cdr (last items)) items))
(mapcar #'funcall
(make-cycled #'identity (lambda (x) (* 2 x)))
'(10 9 8 7 6 5 4 3))
;;=> (10 18 8 14 6 10 4 6)
You could use the loop "on" list iteration primitive. This takes a list of loop variables that will be "smeared" across the list, with the last being the tail of the entire remaining list. The conditional loop for is necessary to avoid multiplying nil if we have an odd number of arguments.
(defun double-every-other (list)
(loop for (single double tail) on list by #'cddr
if (null double)
collect single
else
append (list single (* 2 double))))
And if we try to run it:
* (double-every-other '(1 2 3 4 5))
(1 4 3 8 5)
I am a newbie in clojure and came across a problem which says, multiply first n elements in a sequence by some number 'x' (non recursively). So for example
(multiply-n-by-x [1 2 3 4 5] 2 10) => [10 20 30 4 5]
So here i understood that i need to loop over the sequence n times and then stop, but i am unable to do that. If someone could guide me on how to do about it, it would be great.
Same as Shawn's answer but with destructuring and split-at (a bit less redundant):
(defn multiply-n-by-x [s n x]
(let [[s1 s2] (split-at (inc n) s)]
(concat (map #(* x %) s1) s2)))
I think the easy way is :
(defn multiply-n-by-x [seq n m]
(concat (map #(* m %) (take (inc n) seq)) (drop (inc n) seq) )
)
This does what you want:
(defn multiply-n-by-x [sq n x]
(for [i (range (count sq)) ;for i in range 0 to number of elements in sq
:let [element (nth sq i)]] ;bind element to the nth item in sq
(if (<= i n) ;if index below n, return the multiplied element, otherwise return the element as is
(* x element)
element)))
whatever you return inside the for macro gets put into a sequence so the end result is collection.
Lazy sequences capture delayed recursion. take, drop, split and for are lazy constructions. We can avoid them by computing the altered head of the sequence eagerly, as follows:
(defn multiply-n-by-x [coll n x]
(loop [head [], coll coll, n n]
(if (and (seq coll) (>= n 0))
(recur (conj head (* (first coll) x)) (rest coll) (dec n))
(concat head coll))))
For example,
(multiply-n-by-x [1 2 3 4 5] 2 10)
;(10 20 30 4 5)
By the way, the convention in Clojure is to give the count of a slice, not the index of the final element, which is one less.
(range 3)
;(0 1 2)
In Clojure, I want to be able to multiply all numbers in a set and add them all to a new set to return.
=>(multiply-all #{ 1 2 3})
#{1 4 6 3 2 9}
Here's my implementation:
(defn multiply-all [num-set]
(loop [new-set num-set
cur-set num-set]
(if (= 0 (count cur-set)) new-set
(recur (into new-set (map #(* (first cur-set) %) num-set)) (rest cur-set)))))
Is there a way to do this using doseq WITHOUT using transients. Something like this:
(let [s #{ 1 2 3}]
(doseq [outer s]
(doseq [inner s]
(let [multiplied (* outer inner)]
(println (conj s multiplied))
))))
I'm interested in any suggestions for a cleaner way to do this.
---EDIT----
Here's another way using reduce:
(defn multiply-all2 [num-set]
(let [step (fn [[ result ] mult]
[(into result (map #(* mult %) num-set))])]
(first (reduce step [num-set] num-set))))
doseq is for side effects. You probably want to use for instead:
user=> (set (for [a #{1 2 3}
b #{1 2 3}]
(* a b)))
#{1 4 6 3 2 9}
(defn multiply-all [s]
(set (mapcat #(map * s (repeat %)) s)))
I am trying to set each element of a vector equal to 3 by looping. I get:
java.lang.ClassCastException: clojure.lang.PersistentVector can
not be cast to java.lang.Number
This is the code.
(def w [1 2 3])
(defn update [index value]
(assoc w index value))
(loop [i -1]
(if (< (count w) i)
w
(recur (update (+ i 1) 3))))
Your update function doesn't work the way you expect.
(assoc w index value)
Produces a new vector based on w, except that the element at index is now value. It doesn't change w.
user> (def w [1 2 3])
user> (assoc w 0 9)
[9 2 3]
user> w
[1 2 3]
Also, you're not using loop/recur correctly. You begin the loop with i bound to -1, intending to use it as an index into w, but recur calls the loop not with the next value of i, but rather with an altered copy of w as returned by update.
Try something more like:
(def w [1 2 3])
(loop [i 0, v w]
(if (< (count w) i)
v
(recur (inc i) (assoc v i 3))))
But, since you're not actually using the index to compute the new value of the element, you can use map instead of loop. Since just setting each element to a constant value without considering its old value, you can use clojure's built-in function constantly.
(vec (map (constantly 3) w))
Map returns a sequence, I've wrapped it in a call to vec to transform it back into a vector.
You are mixing integer and vector type by passing (update ...) to recur function. The loop statement should be look like (loop [i -1 w w] ..) and then you could collect your new vector into the local "w". If you want to use recure statement this code can help you (I guess there are a lot of other options to change values of a vector):
(let [value 4
w [1 2 3]]
(loop [i 0
w w]
(if (< i (count w))
(recur (inc i) (assoc w i value))
w)))
You can do this with map and constantly:
(def w [1 2 3])
(map (constantly 3) w)
=> (3 3 3)
Note that this doesn't change w - it returns a new sequence of threes that is the same length as w. Therefore you could equally get the same result by using:
(repeat (count w) 3)
=> 3
If you actually want to change w, then I would suggest making w into an atom so it can be updated with a swap! function:
(def w (atom [1 2 3]))
(swap! w
(fn [old-w]
(vec (map (constantly 3) old-w))))
#w
=> [3 3 3]
Finally, if you really want to update the elements of w one at a time, you can do something like:
(dotimes [i (count #w)]
(swap! w
(fn [previous-w]
(assoc previous-w i 3))))
This seems rather unidiomatic and imperative in Clojure, but it does work.....