Clojure - map a partition over a sequence - functional-programming

I have two collections of the same size - I have partitioned the first one and would like to apply the same partition to the second one. Is there an elegant way of doing this? I have found the following but it seems ugly...
(def x (range 50 70))
(def y [(range 5) (range 10) (range 3) (range 2)] ;my partition of 20 items
(drop-last
(reduce (fn [a b] (concat (drop-last a)
(split-at (count b) (last a))))
[x] y))

i would propose a slightly different approach, using the collections manipulation functions:
(defn split-like [pattern data]
(let [sizes (map count pattern)]
(->> sizes
(reductions #(drop %2 %1) data)
(map take sizes))))
user> (split-like y x)
;;=> ((50 51 52 53 54) (55 56 57 58 59 60 61 62 63 64) (65 66 67) (68 69))
the idea is to collect corresponding tails by reductions with drop:
user> (reductions (fn [acc x] (drop x acc)) (range 20) [1 2 3 4])
;;=> ((0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
;; (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
;; (3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
;; (6 7 8 9 10 11 12 13 14 15 16 17 18 19)
;; (10 11 12 13 14 15 16 17 18 19))
and then just to take needed amounts from that tails:
user> (map take [1 2 3 4] *1)
;;=> ((0) (1 2) (3 4 5) (6 7 8 9))

Similar in spirit to your solution, but I think it is easier to read a straightforward loop/recur structure than a somewhat unconventional reduce:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
; we want to partition x into the same shape as y
(verify
; ideally should have error checking to ensure have enough x values, etc
(let [x (range 50 70)
y [(range 5) (range 10) (range 3) (range 2)] ;my partition of 20 items
lengths (mapv count y)
x2 (loop [xvals x
lens lengths
result []]
(if (empty? lens)
result ; return result when no more segments wanted
(let [len-curr (first lens)
xvals-next (drop len-curr xvals)
lens-next (rest lens)
result-next (conj result (vec (take len-curr xvals)))]
(recur xvals-next lens-next result-next))))]
(is= lengths [5 10 3 2])
(is= x2
[[50 51 52 53 54]
[55 56 57 58 59 60 61 62 63 64]
[65 66 67]
[68 69]])))
When using loop/recur, I quite like the readability of making explicit the *-next values that will be passed into the succeeding loop. I find it unnecessarily difficult to read code that does everything inline in a big, complicated recur form.
Also, since Clojure data is immutable, it doesn't matter that I computer xvals-next before using the current xvals to compute result-next.
Built using my favorite template project.

(require '[com.rpl.specter :as s])
(let [x (range 50 70)
y [(range 5) (range 10) (range 3) (range 2)]]
(s/setval [s/ALL (s/subselect s/ALL)] x y))

Related

Fibonacci sequence less than 1000 in R

I'm trying to print the Fibonacci Sequence less than 1000 using while loop in R.
So far,
fib <- c(1,1)
counter <-3
while (fib[counter-1]<1000){
fib[counter]<- fib[counter-2]+fib[counter-1]
counter = counter+1
}
fib
I have this code. Only the first two numbers are given: 1,1. This is printing:
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
How do I fix my code to print only less than 1000?
Instead of checking the value of the last element wrt 1000, for the expected output you should be checking the sum of the last two elements as so.
fib <- c(1,1)
counter <-3
while (fib[counter-2]+fib[counter - 1]<1000){
fib[counter]<- fib[counter-2]+fib[counter-1]
counter = counter+1
}
fib
The issue with your approach is when the condition (fib[counter-1]<1000) in while loop is FALSE you have already added the number in fib which is greater than 1000.
You could return fib[-length(fib)] to remove the last number or check the number before inserting the number in fib.
fib <- c(1,1)
counter <-3
while (TRUE){
temp <- fib[counter-2] + fib[counter-1]
if(temp < 1000)
fib[counter] <- temp
else
break
counter = counter+1
}
fib
#[1] 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
You could change the while condition to sum the last 2 answers instead of just the last one:
fib <- c(1,1)
counter <-3
while (sum(fib[counter - 1:2]) < 1000){
fib[counter]<- fib[counter-2]+fib[counter-1]
counter = counter+1
}
fib
#> [1] 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
Or just get rid of counter completely:
fib <- c(1,1)
while (sum(fib[length(fib) - 0:1]) < 1000) fib <- c(fib, sum(fib[length(fib) - 0:1]))
fib
#> [1] 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

Why result starts diverging after certain number for Fibonacci sequence?

I'm puzzled with results of computing sequence by different ways:
(defun fig-square-p (n)
"Check if the given N is a perfect square number.
A000290 in the OEIS"
(check-type n (integer 0 *))
(= (floor (sqrt n)) (ceiling (sqrt n))))
(defun fibonaccip (n)
"Check if the given number N is a Fibonacci number."
(check-type n (integer 0 *))
(or (fig-square-p (+ (* 5 (expt n 2)) 4))
(fig-square-p (- (* 5 (expt n 2)) 4))))
(defun fibonacci (n)
"Compute N's Fibonacci number."
(check-type n (integer 0 *))
(loop :for f1 = 0 :then f2
:and f2 = 1 :then (+ f1 f2)
:repeat n :finally (return f1)))
(defun seq-fibonaccies (n)
"Return sequence of Fibonacci numbers upto N."
(check-type n (integer 0 *))
(loop :for i :from 1 :upto n
:collect (fib i)))
CL-USER> (loop :for i :from 0 :upto 7070 :when (fibonaccip i) :collect i)
(0 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 2889 3876 4181 5473
6765 7070)
CL-USER> (seq-fibonaccies 21)
(1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946)
And when I increasing the limit of the loop the results start diverging much more.
~$ sbcl --version
SBCL 1.4.14-3.fc31
As someone else already mentioned, rounding errors accumulate quickly,
so you should stick with the integer arithmetics, using
isqrt:
(defun squarep (n)
"Check if the given N is a perfect square number.
https://oeis.org/A000290"
(check-type n (integer 0 *))
(let ((sqrt (isqrt n)))
(= n (* sqrt sqrt))))
Also, you have a typo in seq-fibonaccies (fib instead of fibonacci).
Finally, seq-fibonaccies is quadratic in its argument, while it only
have to be linear.
fibonaccip is going to give an estimated value because you don't have exact values for the square root of 5. As the value of n increases, the error will also incresase.

Evaluating combination with vectorized function in Julia

In Julia, vectorized function with dot . is used for element-wise manipulation.
Running f.(x) means f(x[1]), f(x[2]),... are sequentially executed
However, suppose I have a function which takes two arguments, say g(x,y)
I want g(x[1],y[1]),g(x[2],y[1]), g(x[3],y[1]), ..., g(x[1],y[2]), g(x[2],y[2]), g(x[3],y[2]), ...
Is there any way to evaluate all combination of x and y?
Matt's answer is good, but I'd like to provide an alternative using an array comprehension:
julia> x = 1:5
y = 10:10:50
[i + j for i in x, j in y]
5×5 Array{Int64,2}:
11 21 31 41 51
12 22 32 42 52
13 23 33 43 53
14 24 34 44 54
15 25 35 45 55
In my opinion the array comprehension can often be more readable and more flexible than broadcast and reshape.
Yes, reshape y such that it is orthogonal to x. The . vectorization uses broadcast to do its work. I imagine this as "extruding" singleton dimensions across all the other dimensions.
That means that for vectors x and y, you can evaluate the product of all combinations of x and y simply by reshaping one of them:
julia> x = 1:5
y = 10:10:50
(+).(x, reshape(y, 1, length(y)))
5×5 Array{Int64,2}:
11 21 31 41 51
12 22 32 42 52
13 23 33 43 53
14 24 34 44 54
15 25 35 45 55
Note that the shape of the array matches the orientation of the arguments; x spans the rows and y spans the columns since it was transposed to a single-row matrix.

if 13* D = 1 mod 60 then D = 37 how?

I am solving an example problem, RSA algorithm
I have been given two prime numbers 7 and 11. Let's say p=7 and q=11
I have to calculate the decryption key, d, for some encryption key, e.
Firstly I calculated n=p*q which implies that n=77.
Suppose that e=13,
to calculate d I used the formula d*e = 1 mod fi,
where fi=(p-1)(q-1), and so fi=60
The final equation becomes 13*d = 1 mod fi
According to some solved example
d is calculated to be 37, how is this result obtained?
Any help would be appreciated.
i think this is what you are looking for
Verifying the answer is easy, finding it in the first place, a little more work.
Verification:
13 * 37 = 481
481 = 8 * 60 + 1
Hence if you divide 13 * 37 by 60 you have remainder 1.
Alternate answers:
Any integer of the form (37 + 60 k) where k is any integer is also a solution. (97, -23, etc.)
To find the solution you can proceed as follows:
Solve:
13 d = 1 + 60 k
mod 13:
0 = 1 + 8k (mod 13)
8k = -1 (mod 13)
Add 13's until a multiple of 8 is found:
8k = 12 or 25 or 38 or 51 or 64 .... aha a multiple of 8!
k = 64 / 8 = 8
Substitute k = 8 back into 13 d = 1 + 60 k
13 d = 1 + 8 * 60 = 481
481 /13 = 37
and that is the answer.
Use the extended Euclidean algorithm to compute integers x and y such that
13*x+60*y=1
Then x is the answer you're looking for, mod 60.

Why isnot the local variable freed?

The test function is as below:
(defun fab (n)
(let ((res '(1 1)))
(loop for i from 2 to n do
(nconc res (list (+ (nth (- i 2) res) (nth (- i 1) res)))))
res))
$ecl
...
EECL (Embeddable Common-Lisp) 12.7.1 (git:UNKNOWN)
...
>(fab 10)
(1 1 2 3 5 8 13 21 34 55 89)
>(fab 20)
(1 1 2 3 5 8 13 21 34 55 89 2 3 5 8 13 21 34 55 89 144 91 5 8 13 21 34 55 89 144
Then i restart ECL
>(fab 20)
(1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946)
It seems the "res" is not freed after the (fac 10) ?
Sincerely!
You should use (list 1 1) rather than '(1 1) in the let form. In Common Lisp, the effects of modifying literal objects are not defined.
(defun fib (n)
(let ((res (list 1 1))) ; (list 1 1) instead of '(1 1)
(loop for i from 2 to n
do (nconc res (list (+ (nth (- i 2) res) (nth (- i 1) res)))))
res))
Constants such as '(1 1) are only allocated once by the compiler / interpreter. Your code uses NCONC on this list, modifying, and subsequent calls do no longer see the constant list '(1 1) but the modified one. In Common Lisp it is unspecified what happens when on destructively modifies constant expressions, and some implementations even protect them against changes to avoid such surprises. If you need a fresh new constant, do as people said and use (list 1 1) or avoid using NCONC altogether.

Resources