Exchange two elements of a vector in one call - r

I have a vector c(9,6,3,4,2,1,5,7,8), and I want to switch the elements at index 2 and at index 5 in the vector. However, I don't want to have to create a temporary variable and would like to make the switch in one call. How would I do that?

How about just x[c(i,j)] <- x[c(j,i)]? Similar to replace(...), but perhaps a bit simpler.
swtch <- function(x,i,j) {x[c(i,j)] <- x[c(j,i)]; x}
swtch(c(9,6,3,4,2,1,5,7,8) , 2,5)
# [1] 9 2 3 4 6 1 5 7 8

You could use replace().
x <- c(9, 6, 3, 4, 2, 1, 5, 7, 8)
replace(x, c(2, 5), x[c(5, 2)])
# [1] 9 2 3 4 6 1 5 7 8
And if you don't even want to assign x, you can use
replace(
c(9, 6, 3, 4, 2, 1, 5, 7, 8),
c(2, 5),
c(9, 6, 3, 4, 2, 1, 5, 7, 8)[c(5, 2)]
)
# [1] 9 2 3 4 6 1 5 7 8
but that's a bit silly. You will probably want x assigned to begin with.

If you actually want to do it without creating a temporary copy of the vector, you would need to write a short C function.
library(inline)
swap <- cfunction(c(i = "integer", j = "integer", vec="integer"),"
int *v = INTEGER(vec);
int ii = INTEGER(i)[0]-1, jj = INTEGER(j)[0]-1;
int tmp = v[ii];
v[ii] = v[jj];
v[jj] = tmp;
return R_NilValue;
")
vec <- as.integer(c(9,6,3,4,2,1,5,7,8))
swap(2L, 5L, vec)
vec
# [1] 9 2 3 4 6 1 5 7 8

Related

How to select a random vector

I have 4 vectors that contain integers.
I want to perform calculations based on 2 of the vectors, selected randomly.
I tried creating a new vector containing all the vectors, but sample() only gives me the first element of each vector.
My vectors if it helps:
A <- c(4, 4, 4, 4, 0, 0)
B <- c(3, 3, 3, 3, 3, 3)
C <- c(6, 6, 2, 2, 2, 2)
D <- c(5, 5, 5, 1, 1, 1)
The output I wanted is for example: A, B or B, D or D, A etc.
A thousand thanks in advance!
This is easier to do if you store your vectors in a list:
vecs <- list(
A = c(4, 4, 4, 4, 0, 0),
B = c(3, 3, 3, 3, 3, 3),
C = c(6, 6, 2, 2, 2, 2),
D = c(5, 5, 5, 1, 1, 1)
)
idx <- sample(1:length(vecs), 2, replace = F)
sampled <- vecs[idx]
sampled
$D
[1] 5 5 5 1 1 1
$B
[1] 3 3 3 3 3 3
You can then access your two sampled vectors, regardless of their names, with sampled[[1]] and sampled[[2]].
You first need make a list or a dataframe, on which you can do sample(). size= says the number of vectors that you want in each sample, which is 2 here.
LIST
> LIST <- list(A, B, C, D)
> sample(LIST, size = 2)
[[1]]
[1] 3 3 3 3 3 3
[[2]]
[1] 4 4 4 4 0 0
Dataframe
> df <- data.frame(A, B, C, D)
> sample(df, size = 2)
B C
1 3 6
2 3 6
3 3 2
4 3 2
5 3 2
6 3 2
I think you were sampling on the wrong object.
Make a list:
LIST = list(A,B,C,D)
names(LIST) = c("A","B","C","D")
This gives you a sample of 2 from the list
sample(LIST,2)
To add them for example, do:
Reduce("+",sample(LIST,2))

How to condense non-sequential integers?

I'm trying to condense non-sequential numbers to subset haplotype data. I could do it manually, but given that I've got hundreds to do, I'd rather not if there's an alternative
class(haplotype1[[1]])
#[1] "integer"
haplotype1[[1]]
#[1] 1 2 3 4 5 7 8 9 10 11
I want to get [1:5, 7:11], which seems simple, but I haven't found a solution exactly matching my problem
Thanks!
Using cumsum to create the sequential groups,
tapply(x, cumsum(c(TRUE, diff(x) != 1)), FUN = function(i)paste(i[1], i[length(i)], sep = ':'))
# 1 2
#"1:5" "7:11"
It's unclear what type of object you want to create. I would just store the start and end values.
x <- c(1, 2, 3, 4, 5, 7, 8, 9, 10, 11)
starts <- x[!c(FALSE, diff(x) == 1L)]
#[1] 1 7
ends <- x[!c(diff(x) == 1L, FALSE)]
#[1] 5 11
paste(starts, ends, sep = ":")
#[1] "1:5" "7:11"
Maybe you want something like this ?
vec <- c(1, 2, 3, 4, 5, 7, 8, 9, 10, 11)
split(vec, cumsum(c(1,diff(vec)>1)))
# $`1`
# [1] 1 2 3 4 5
#
# $`2`
# [1] 7 8 9 10 11

average calculation for many data in R

I have a file to which the results are saved:
4
4
4
4
5
4
4
5
6
4
4
5
5
6
4
I would like to calculate the average for each group
unfortunately, only I managed to calculate for everyone
I would like to get an average of 5 items
they are savedin wynik2.txt file
wynik_epidemii <- read.table(file="wynik2.txt")
wynik_epidemii<- mean(as.numeric(unlist(wynik_epidemii)))
You can use tapply, defining the grouping factor with a cumsum trick.
meanN <- function(x, n = 5){
f <- cumsum(rep(c(1, rep(0, n - 1)), length.out = length(x)))
tapply(x, f, mean)
}
meanN(x)
# 1 2 3
#4.2 4.6 4.8
DATA.
x <-
c(4, 4, 4, 4, 5, 4, 4, 5, 6, 4, 4, 5, 5, 6, 4)

Count occurence of multiple numbers in vector one by one

I have two vectors
a <- c(1, 5, 2, 1, 2, 3, 3, 4, 5, 1, 2)
b <- (1, 2, 3, 4, 5, 6)
I want to know how many times each element in b occurs in a. So the result should be
c(3, 3, 2, 1, 2, 0)
All methods I found like match(),==, %in% etc. are not suited for entire vectors. I know I can use a loop over all elements in b,
for (i in 1:length(b)) {
c[I] <- sum(a==b, na.rm=TRUE)
}
but this is used often and takes to long. That's why I'm looking for a vectorized way, or a way to use apply().
You can do this using factor and table
table(factor(a, unique(b)))
#
#1 2 3 4 5 6
#3 3 2 1 2 0
Since you mentioned match, here is a possibility without sapply loop (thanks to #thelatemail)
table(factor(match(a, b), unique(b)))
#
#1 2 3 4 5 6
#3 3 2 1 2 0
Here is a base R option, using sapply with which:
a <- c(1, 5, 2, 1, 2, 3, 3, 4, 5, 1, 2)
b <- c(1, 2, 3, 4, 5, 6)
sapply(b, function(x) length(which(a == x)))
[1] 3 3 2 1 2 0
Demo
Here is a vectorised method
x = expand.grid(b,a)
rowSums( matrix(x$Var1 == x$Var2, nrow = length(b)))
# [1] 3 3 2 1 2 0

how to get index of sorted array elements

Say I have an array in R : c(10, 7, 4, 3, 8, 2)
Upon sorting, this would be : c(2, 3, 4, 7, 8, 10)
What is the best way in R to return the indices for the sorted array elements from the original array. I'm looking for an output like :
6(index of 2), 4(index of 3), 3(index of 4), 2(index of 7), 5(index of 8), 1(index of 10)
The function you're looking for is order:
> x
[1] 10 7 4 3 8 2
> order(x)
[1] 6 4 3 2 5 1
sort has index.return argument, which by default is FALSE
x <- c(10,7,4,3,8,2)
sort(x, index.return=TRUE) #returns a list with `sorted values`
#and `$ix` as index.
#$x
#[1] 2 3 4 7 8 10
#$ix
#[1] 6 4 3 2 5 1
You can extract the index by
sort(x, index.return=TRUE)$ix
#[1] 6 4 3 2 5 1

Resources