In Clojure, I can have a sequence a..b with (range a b). But this is a lazy sequence as I understand. Can I just generate a list and/or vector of numbers a..b?
Note: I am new to Clojure.
do you mean something like
user> (vec (range 2 7))
[2 3 4 5 6]
user> (apply list (range 2 7))
(2 3 4 5 6)
user> (into [] (range 2 7))
[2 3 4 5 6]
user> (into '() (range 2 7))
(6 5 4 3 2) ; <-- note the order
user> (into #{} (range 2 7))
#{2 3 4 5 6}
Related
Ok so i have an algorithm what it does is , it loops through a fill line by line and then looks for a given word in the line. Not only does it return the given word but it also returns a number(given also as a parameter) of words that come before and after that word.
Eg.line = "I am overflowing with blessings and you also are"
parameters = ("you" 2)
output = (blessings and you also are)
(with-open [r (clojure.java.io/reader "resources/small.txt")]
(doseq [l (line-seq r)]
(let [x (topMostLoop l "good" 2)]
(if (not (empty? x))
(println x)))))
the above code is working fine. But i would like to parallelize it so i did this below
(with-open [r (clojure.java.io/reader "resources/small.txt")]
(doseq [l (line-seq r)]
(future
(let [x (topMostLoop l "good" 2)]
(if (not (empty? x))
(println x))))))
but then the outputs comes out all messy. I know I need to lock somewhere but dont know where.
(defn topMostLoop [contents word next]
(let [mywords (str/split contents #"[ ,\\.]+")]
(map (fn [element] (
return-lines (max 0 (- element next))
(min (+ element next) (- (count mywords) 1)) mywords))
(vec ((indexHashMap mywords) word)))))
Please would be glad if someone can help me this is the last thing Im left with.
NB. Do let me know if i need to post the other functions as well
I have added the other functions for more clarity
(defn return-lines [firstItem lastItem contentArray]
(take (+ (- lastItem firstItem) 1)
(map (fn [element] (str element))
(vec (drop firstItem contentArray)))))
(defn indexHashMap [mywords]
(->> (zipmap (range) mywords) ;contents is a list of words
(reduce (fn [index [location word]]
(merge-with concat index {word (list location)})) {})))
First, use map for first example when you are using serial approach:
(with-open [r (clojure.java.io/reader "resources/small.txt")]
(doseq [l (map #(topMostLoop %1 "good" 2) (line-seq r))]
(if (not (empty? l))
(println l))))
With this approach topMostLoop function is applied on each line, and lazy seq of results is returned. In body of doseq function results are printed if not empty.
After that, replace map with pmap, which will run mapping in parallel, and results will appear in same order as given lines:
(with-open [r (clojure.java.io/reader "resources/small.txt")]
(doseq [l (pmap #(topMostLoop %1 "good" 2) (line-seq r))]
(if (not (empty? l))
(println l))))
In your case with futures, results will be normaly out of order (some later futures will finish execution sooner than former futures).
I tested this with following modifications (not reading text file, but creating lazy sequence of vector of numbers, searching for value in vectors and returning surrounding):
(def lines (repeatedly #(shuffle (range 1 11))))
(def lines-10 (take 10 lines))
lines-10
([5 8 3 10 6 9 7 2 1 4]
[6 8 9 7 2 5 10 4 1 3]
[2 7 8 9 1 5 10 3 4 6]
[10 8 3 5 7 2 4 9 6 1]
[8 6 10 1 9 4 3 7 2 5]
[9 6 8 1 5 10 3 4 2 7]
[10 9 3 7 1 8 4 6 5 2]
[6 1 4 10 3 7 8 9 5 2]
[9 6 7 5 8 3 10 4 2 1]
[4 1 5 2 7 3 6 9 8 10])
(defn surrounding
[v value size]
(let [i (.indexOf v value)]
(if (= i -1)
nil
(subvec v (max (- i size) 0) (inc (min (+ i size) (dec (count v))))))))
(doseq [l (map #(surrounding % 3 2) lines-10)] (if (not (empty? l)) (println l)))
[5 8 3 10 6]
[4 1 3]
[5 10 3 4 6]
[10 8 3 5 7]
[9 4 3 7 2]
[5 10 3 4 2]
[10 9 3 7 1]
[4 10 3 7 8]
[5 8 3 10 4]
[2 7 3 6 9]
nil
(doseq [l (pmap #(surrounding % 3 2) lines-10)] (if (not (empty? l)) (println l)))
[5 8 3 10 6]
[4 1 3]
[5 10 3 4 6]
[10 8 3 5 7]
[9 4 3 7 2]
[5 10 3 4 2]
[10 9 3 7 1]
[4 10 3 7 8]
[5 8 3 10 4]
[2 7 3 6 9]
nil
I would also like the changed value to be random. For example
'(1 2 3 4 5)
one possible output.
'(1 3 3 4 5)
another
'(1 5 5 4 5)
there are more idiomatic ways to do this in clojure. For example this one:
you can generate infinite lazy sequence of random changes to the initial collection, and then just take a random item from it.
(defn random-changes [items limit]
(rest (reductions #(assoc %1 (rand-int (count items)) %2)
(vec items)
(repeatedly #(rand-int limit)))))
in repl:
user> (take 5 (random-changes '(1 2 3 4 5 6 7 8) 100))
([1 2 3 4 5 64 7 8] [1 2 3 4 5 64 58 8] [1 2 3 4 5 64 58 80]
[1 2 3 4 5 28 58 80] [1 2 3 71 5 28 58 80])
user> (nth (random-changes '(1 2 3 4 5 6 7 8) 100) 0)
[1 2 3 64 5 6 7 8]
and you can just take an item at the index you want (so it means collection with index + 1 changes).
user> (nth (random-changes '(1 2 3 4 5 6 7 8) 100) (rand-int 3))
[1 46 3 44 86 6 7 8]
or just use reduce to take the n times changed coll at once:
(defn random-changes [items limit changes-count]
(reduce #(assoc %1 (rand-int (count items)) %2)
(vec items)
(repeatedly changes-count #(rand-int limit))))
in repl:
user> (random-changes [1 2 3 4 5 6] 100 3)
[27 2 33 4 76 6]
also you can just associate all the changes in a vector at once:
(assoc items 0 100 1 200 2 300), so you can do it like that:
(defn random-changes [items limit changes-count]
(let [items (vec items)
rands #(repeatedly changes-count (partial rand-int %))]
(apply assoc items
(interleave (rands (count items))
(rands limit)))))
in repl:
user> (random-changes [1 2 3 4 5 6] 100 3)
[1 65 61 44 5 6]
Figured it out. Decided to go a longer route and make a function.
(defn changeSequence
[sequ x]
(def transsequ (into [] sequ))
(if (> x 0)
(changeSequence (assoc transsequ (rand-int (count transsequ)) (rand-int foo)) (dec x))
(seq sequ)
))
Say I have the sequence:
[1 2 3 4 5]
And I want to map over them in the pairs:
[(1, 2), (2, 3), (3, 4), (4, 5)]
I have tried:
(map f (partition 2 [1 2 3 4]))
But this results in the sequence of pairs:
[(1, 2), (3, 4)]
How can I get the desired functionality?
By default partiton returns non-overlapping partitions, but you can supply a step argument to provide the offset at which partitions are created:
clojure.core/partition
([n coll] [n step coll] [n step pad coll])
Returns a lazy sequence of lists of n items each, at offsets step
apart. If step is not supplied, defaults to n, i.e. the partitions
do not overlap. If a pad collection is supplied, use its elements as
necessary to complete last partition upto n items. In case there are
not enough padding elements, return a partition with less than n items.
This will do what you want:
(partition 2 1 [1 2 3 4 5 6 7 8]))
; #=> ((1 2) (2 3) (3 4) (4 5) (5 6) (6 7) (7 8))
An alternative would be map both with the list you have and the rest of the list. E.g.:
(user=> (let [l [1 2 3 4 5]] (map list l (rest l)))
((1 2) (2 3) (3 4) (4 5))
I would do it as follows
; first generate data
; (that is if you really are talking about all the ints)
(map (juxt identity inc) [1 2 3 4 5])
=> ([1 2] [2 3] [3 4] [4 5] [5 6])
; inline example
(map (comp
(fn [[a b]] (println a b)) ; this would be your f
(juxt identity inc)) [1 2 3 4 5])
; using your function f
(map (comp
f
(juxt identity inc)) [1 2 3 4 5])
This also works independent of the order of numbers in your vector:
(let [a [5 4 3 2 1] b (rest a)] (map vector a b))
will yield:
([5 4] [4 3] [3 2] [2 1])
I would like to partition a seq, based on a seq of values
(partition-by-seq [3 5] [1 2 3 4 5 6])
((1 2 3)(4 5)(6))
The first input is a seq of split points.
The second input is a seq i would like to partition.
So, that the first list will be partitioned at the value 3 (1 2 3) and the second partition will be (4 5) where 5 is the next split point.
another example:
(partition-by-seq [3] [2 3 4 5])
result: ((2 3)(4 5))
(partition-by-seq [2 5] [2 3 5 6])
result: ((2)(3 5)(6))
given: the first seq (split points) is always a subset of the second input seq.
I came up with this solution which is lazy and quite (IMO) straightforward.
(defn part-seq [splitters coll]
(lazy-seq
(when-let [s (seq coll)]
(if-let [split-point (first splitters)]
; build seq until first splitter
(let [run (cons (first s) (take-while #(<= % split-point) (next s)))]
; build the lazy seq of partitions recursively
(cons run
(part-seq (rest splitters) (drop (count run) s))))
; just return one partition if there is no splitter
(list coll)))))
If the split points are all in the sequence:
(part-seq [3 5 8] [0 1 2 3 4 5 6 7 8 9])
;;=> ((0 1 2 3) (4 5) (6 7 8) (9))
If some split points are not in the sequence
(part-seq [3 5 8] [0 1 2 4 5 6 8 9])
;;=> ((0 1 2) (4 5) (6 8) (9))
Example with some infinite sequences for the splitters and the sequence to split.
(take 5 (part-seq (iterate (partial + 3) 5) (range)))
;;=> ((0 1 2 3 4 5) (6 7 8) (9 10 11) (12 13 14) (15 16 17))
the sequence to be partitioned is a splittee and the elements of split-points (aka. splitter) marks the last element of a partition.
from your example:
splittee: [1 2 3 4 5 6]
splitter: [3 5]
result: ((1 2 3)(4 5)(6))
Because the resulting partitions is always a increasing integer sequence and increasing integer sequence of x can be defined as start <= x < end, the splitter elements can be transformed into end of a sequence according to the definition.
so, from [3 5], we want to find subsequences ended with 4 and 6.
then by adding the start, the splitter can be transformed into sequences of [start end]. The start and end of the splittee is also used.
so, the splitter [3 5] then becomes:
[[1 4] [4 6] [6 7]]
splitter transformation could be done like this
(->> (concat [(first splittee)]
(mapcat (juxt inc inc) splitter)
[(inc (last splittee))])
(partition 2)
there is a nice symmetry between transformed splitter and the desired result.
[[1 4] [4 6] [6 7]]
((1 2 3) (4 5) (6))
then the problem becomes how to extract subsequences inside splittee that is ranged by [start end] inside transformed splitter
clojure has subseq function that can be used to find a subsequence inside ordered sequence by start and end criteria. I can just map the subseq of splittee for each elements of transformed-splitter
(map (fn [[x y]]
(subseq (apply sorted-set splittee) <= x < y))
transformed-splitter)
by combining the steps above, my answer is:
(defn partition-by-seq
[splitter splittee]
(->> (concat [(first splittee)]
(mapcat (juxt inc inc) splitter)
[(inc (last splittee))])
(partition 2)
(map (fn [[x y]]
(subseq (apply sorted-set splittee) <= x < y)))))
This is the solution i came up with.
(def a [1 2 3 4 5 6])
(def p [2 4 5])
(defn partition-by-seq [s input]
(loop [i 0
t input
v (transient [])]
(if (< i (count s))
(let [x (split-with #(<= % (nth s i)) t)]
(recur (inc i) (first (rest x)) (conj! v (first x))))
(do
(conj! v t)
(filter #(not= (count %) 0) (persistent! v))))))
(partition-by-seq p a)
(def tmp = [ 1 2 3 9 4 8])
I'm trying to create pairs of 2, then for each pair, subtract the second number from the first.
desired result: (1 6 4)
Here is what I was trying:
(map #(apply - %2 %1) (partition 2 tmp))
how can I do this?
Partition produces a sequence of sequences so the function you map over them needs to expect a sequence of two items. There are several ways to express this:
(def tmp [ 1 2 3 9 4 8])
user> (map #(- (second %) (first %)) (partition-all 2 tmp ))
(1 6 4)
user> (map #(apply - (reverse %)) (partition-all 2 tmp ))
(1 6 4)
user> (map (fn [[small large]] (- large small)) (partition-all 2 tmp ))
(1 6 4)
The version using apply is different because it will still "work" on odd length lists:
user> (map #(apply - (reverse %)) (partition-all 2 [1 2 3 4 5 6 7] ))
(1 1 1 -7)
The others will crash on invalid input, which you may prefer.
Here's a solution using reduce
(reduce #(conj %1 (apply - (reverse %2))) [] (partition-all 2 [1 2 3 9 4 8]))
=> [1 6 4]
I wonder why this solution was overlooked...
Since switching the order of subtraction is simply the negative of the original subtraction, (a-b=-(b-a)),
the solution becomes more efficient (only in this particular case!!)
(map #(- (apply - %)) (partition-all 2 [1 2 3 9 4 8]))
Pedagogically, Arthur's solution is correct. This is just a solution that is more suited the specfic question.