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))
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
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.
I have a vector and I need to sum every n numbers and return the results. This is the way I plan on doing it currently. Any better way to do this?
v = 1:100
n = 10
sidx = seq.int(from=1, to=length(v), by=n)
eidx = c((sidx-1)[2:length(sidx)], length(v))
thesum = sapply(1:length(sidx), function(i) sum(v[sidx[i]:eidx[i]]))
This gives:
thesum
[1] 55 155 255 355 455 555 655 755 855 955
unname(tapply(v, (seq_along(v)-1) %/% n, sum))
# [1] 55 155 255 355 455 555 655 755 855 955
UPDATE:
If you want to sum every n consecutive numbers use colSums
If you want to sum every nth number use rowSums
as per Josh's comment, this will only work if n divides length(v) nicely.
rowSums(matrix(v, nrow=n))
[1] 460 470 480 490 500 510 520 530 540 550
colSums(matrix(v, nrow=n))
[1] 55 155 255 355 455 555 655 755 855 955
Update
The olde version don't work. Here a ne awnser that use rep to create the grouping factor. No need to use cut:
n <- 5
vv <- sample(1:1000,100)
seqs <- seq_along(vv)
tapply(vv,rep(seqs,each=n)[seqs],FUN=sum)
You can use tapply
tapply(1:100,cut(1:100,10),FUN=sum)
or to get a list
by(1:100,cut(1:100,10),FUN=sum)
EDIT
In case you have 1:92, you can replace your cut by this :
cut(1:92,seq(1,92,10),include.lowest=T)
One way is to convert your vector to a matric then take the column sums:
colSums(matrix(v, nrow=n))
[1] 55 155 255 355 455 555 655 755 855 955
Just be careful: this implicitly assumes that your input vector can in fact be reshaped to a matrix. If it can't, R will recycle elements of your vector to complete the matrix.
v <- 1:100
n <- 10
cutpoints <- seq( 1 , length( v ) , by = n )
categories <- findInterval( 1:length( v ) , cutpoints )
tapply( v , categories , sum )
I will add one more way of doing it without any function from apply family
v <- 1:100
n <- 10
diff(c(0, cumsum(v)[slice.index(v, 1)%%n == 0]))
## [1] 55 155 255 355 455 555 655 755 855 955
Here are some of the main variants offered so far
f0 <- function(v, n) {
sidx = seq.int(from=1, to=length(v), by=n)
eidx = c((sidx-1)[2:length(sidx)], length(v))
sapply(1:length(sidx), function(i) sum(v[sidx[i]:eidx[i]]))
}
f1 <- function(v, n, na.rm=TRUE) { # 'tapply'
unname(tapply(v, (seq_along(v)-1) %/% n, sum, na.rm=na.rm))
}
f2 <- function(v, n, na.rm=TRUE) { # 'matrix'
nv <- length(v)
if (nv %% n)
v[ceiling(nv / n) * n] <- NA
colSums(matrix(v, n), na.rm=na.rm)
}
f3 <- function(v, n) { # 'cumsum'
nv = length(v)
i <- c(seq_len(nv %/% n) * n, if (nv %% n) nv else NULL)
diff(c(0L, cumsum(v)[i]))
}
Basic test cases might be
v = list(1:4, 1:5, c(NA, 2:4), integer())
n = 2
f0 fails with the final test, but this could probably be fixed
> f0(integer(), n)
Error in sidx[i]:eidx[i] : NA/NaN argument
The cumsum approach f3 is subject to rounding error, and the presence of an NA early in v 'poisons' later results
> f3(c(NA, 2:4), n)
[1] NA NA
In terms of performance, the original solution is not bad
> library(rbenchmark)
> cols <- c("test", "elapsed", "relative")
> v <- 1:100; n <- 10
> benchmark(f0(v, n), f1(v, n), f2(v, n), f3(v, n),
+ columns=cols)
test elapsed relative
1 f0(v, n) 0.012 3.00
2 f1(v, n) 0.065 16.25
3 f2(v, n) 0.004 1.00
4 f3(v, n) 0.004 1.00
but the matrix solution f2 seems to be both fast and flexible (e.g., adjusting the handling of that trailing chunk of fewer than n elements)
> v <- runif(1e6); n <- 10
> benchmark(f0(v, n), f2(v, n), f3(v, n), columns=cols, replications=10)
test elapsed relative
1 f0(v, n) 5.804 34.141
2 f2(v, n) 0.170 1.000
3 f3(v, n) 0.251 1.476
One way is to use rollapply from zoo:
rollapply(v, width=n, FUN=sum, by=n)
# [1] 55 155 255 355 455 555 655 755 855 955
And in case length(v) is not a multiple of n:
v <- 1:92
rollapply(v, width=n, FUN=sum, by=n, partial=T, align="left")
# [1] 55 155 255 355 455 555 655 755 855 183
A little late to the party, but I don't see a rowsum() answer yet. rowsum() is proven more efficient than tapply() and I think it would also be very efficient relative to a few of the other responses as well.
rowsum(v, rep(seq_len(length(v)/n), each=n))[,1]
# 1 2 3 4 5 6 7 8 9 10
# 55 155 255 355 455 555 655 755 855 955
Using #Josh O'Brien's grouping technique would likely improve efficiency even more.
rowsum(v, (seq_along(v)-1) %/% n)[,1]
# 0 1 2 3 4 5 6 7 8 9
# 55 155 255 355 455 555 655 755 855 955
Simply wrap in unname() to drop the group names.
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.