Locating the row and col number with the entry number in R - r

I am trying to find the row and column numbers of a matrix once I have the entry number. For example if I am trying to find a 0 in a matrix full of numbers I would try something like this
test_array <- array(1,c(30,30))
test_array[200] <- 0
counter <- 0
for(i in test_array){
counter <- counter + 1
if(i == 0){
print(counter)
}
}
200
So now I know that at position 200 I have a 0 but how do I check where it is in terms of its row and col.
Something like (15, 8)

You can use the arr.ind argument in which:
which(test_array == 0, arr.ind = TRUE)
#> row col
#> [1,] 20 7

Related

Generate random values in array until a total value is reached in R [duplicate]

This question already has answers here:
Generate N random integers that sum to M in R
(3 answers)
Closed 10 days ago.
I want to create an array, then assign a value to each place until the sum of values in the array equals a given total. Once the maximum value is reached the rest of the array can be 0. So to start:
years <- 20 # total length of array
N <- array(0, years) # make array
tot <- 10 # Total I want to stop at
max.size <- 3 # maximum value to put in the array
So the result may look something like: N = c(1,3,0,2,0,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0)
I think a while statement would work, similar to this question, but not sure how to get there. Also, I think this question has the pieces I need, but am struggling to put them into my context.
random.sample <- function(x) { repeat {
# do something
i <- sample(0:max.size, 1)
x <- i
# exit if the condition is met
if (sum(x) == tot) break } return(x) }
random.sample(N)
Thanks for your time.
A simple function using cumsum and ifelse would do the job without requiring costly loops. The last clause just ensures the the numbers add to tot
f <- function(len, tot, max.size) {
x <- sample(0:max.size, len, replace = TRUE)
res <- ifelse(cumsum(x) > tot, 0, x)
if(sum(res) < tot) {
res[(cumsum(res) == sum(res)) & res == 0][1] <- tot - sum(res)
}
res
}
Testing
f(len = 20, tot = 10, max.size = 3)
#> [1] 3 3 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

For and If in R data programming

I want to evaluate the distance between non-zero data. So if i have 50 data, and only the first and last data is non-zero, thus i want the result to be 49.
For example, my data is:
1. 0
2. 0
3. 5
4. 6
5. 0
6. 1
7. 0
Based on my data above, i want to get 4 variables:
v0 = 3 (because the distance between 0th to 3rd data is 3 jumps)
v1 = 1 (because the distance between 3rd to 4th data is 1 jump)
v2 = 2 (because the distance between 4rd to 6th data is 2 jump)
v3 = 1 (because the distance between 6rd to 7th data is 1 jump)
This is my code:
data=c(0,0,5,6,0,1,0)
t=1
for (i in data) {
if (i == 0) {
t[i]=t+1
}
else {
t[i]=1
}
}
t
The result is:
[1] 1 NA NA NA 1 1
Could you help me in figuring out this problem? I also hope that the code is using some kind of loop, so that it can be applied to any other data.
The general rule is not clear from the question but if x is the input we assume that:
the input is non-negative
the first element in output is the position of the first +ve element in x
subsequent elements of output are distances between successive +ve elements of x
if that results in a vector whose sum is less than length(x) append the remainder
To do that determine the positions of the positive elements of c(1, x), calculate the differences between successive elements in that reduced vector using diff and then if they don't sum to length(x) append the remainder.
dists <- function(x) {
d <- diff(which(c(1, x) > 0))
if (sum(d) < length(x)) c(d, length(x) - sum(d)) else d
}
# distance to 5 is 3 and then to 6 is 1 and then to 1 is 2 and 1 is left
x1 <- c(0, 0, 5, 6, 0, 1, 0)
dists(x1)
## [1] 3 1 2 1
# distance to first 1 is 1 and from that to second 1 is 3
x2 <- c(1, 0, 0, 1)
dists(x2)
## [1] 1 3
Here it is redone using a loop:
dists2 <- function(x) {
pos <- 0
out <- numeric(0)
for(i in seq_along(x)) {
if (x[i]) {
out <- c(out, i - pos)
pos <- i
}
}
if (sum(out) < length(x)) out <- c(out, length(x) - sum(out))
out
}
dists2(x1)
## [1] 3 1 2 1
dists2(x2)
## [1] 1 3
Updates
Simplification based on comments below answer. Added loop approach.

Cut elements from the beginning and end of an R vector

For time series analysis I handle data that often contains leading and trailing zero elements. In this example, there are 3 zeros at the beginning an 2 at the end. I want to get rid of these elements, and filter for the contents in the middle (that also may contain zeros)
vec <- c(0, 0, 0, 1, 2, 0, 3, 4, 0, 0)
I did this by looping from the beginning and end, and masking out the unwanted elements.
mask <- rep(TRUE, length(vec))
# from begin
i <- 1
while(vec[i] == 0 && i <= length(vec)) {
mask[i] <- FALSE
i <- i+1
}
# from end
i <- length(vec)
while(i >= 1 && vec[i] == 0) {
mask[i] <- FALSE
i <- i-1
}
cleanvec <- vec[mask]
cleanvec
[1] 1 2 0 3 4
This works, but I wonder if there is a more efficient way to do this, avoiding the loops.
vec[ min(which(vec != 0)) : max(which(vec != 0)) ]
Basically the which(vec != 0) part gives the positions of the numbers that are different from 0, and then you take the min and max of them.
We could use the range and Reduce to get the sequence
vec[Reduce(`:`, range(which(vec != 0)))]
#[1] 1 2 0 3 4
Take the cumsum forward and backward of abs(vec) and keep only elements > 0. if it were known that all elements of vec were non-negative, as in the question, then we could optionally omit abs.
vec[cumsum(abs(vec)) > 0 & rev(cumsum(rev(abs(vec)))) > 0]
## [1] 1 2 0 3 4

R: Remove repeated values and keep the first one in a binary vector

I would like to remove the repeated ones but keep the first in a binary vector:
x = c(0,0,1,1,0,1,0,1,1,1,0,1) # the input
y = c(0,0,1,0,1,0,1,0,1) # the desired output
i.e., one 1 and two 1's of the first and third set of 1's are removed, respectively, and the first in the set is kept.
I am trying to use rle with cumsum but have not yet figured it out. Any suggestion would be appreciated.
Using rle/inverse.rle
res <- rle(x)
res$lengths[res$values == 1] <- 1
inverse.rle(res)
## [1] 0 0 1 0 1 0 1 0 1
We can use diff:
x[c(1, diff(x)) == 1 | x == 0]
x = c(0,0,1,1,0,1,0,1,1,1,0,1)
x[!(x == 1 & #remove each value that is a 1
c(x[-1] == 1, FALSE) #followed by a 1 (never the case for the last value)
)]
#[1] 0 0 1 0 1 0 1 0 1
x = c(0,0,1,1,0,1,0,1,1,1,0,1)
x1 <- rle(x)
x1$lengths[x1$values==1] <- 1
inverse.rle(x1)
Depending on the vector size you could loop through it and use conditions for appending the value to the result. Here is a simple solution using your given input.
x <- c(0,0,1,1,0,1,0,1,1,1,0,1)
prev <- 0
y <- c()
for(i in x){
if (i == 1){
if (prev != 1){
y <- append(y,i)
}
}else{
y <- append(y,i)
}
prev <- i
}

argument of length 0 in for loop R

I have 2 vectors of numbers. The vector "v" shows when a process starts in seconds. Vector u shows how much time does the proces in the vector u works.
I want to creeate a vector saying how many process are working at each second.
so this toy example: I create a vector "total" thats starts in second 0 (nevermind the end of the vector) and I will save in each position how many processes work in that second. So for example, in the first position of the vector(time 0) my code says I will have 1 process.
v <- c(0,1,2,3,4,5)
u <- c(1.2, 0.1, 1.2, 1, 0.5, 0)
j = 1
total <- rep(0, times = 10)
begin <- integer()
end <- integer()
repeat{
begin<- v[j] +1
end <- begin + u[j]%/%1
for(i in begin:end){
if(total[i] == 0){ total[i] <-1}
else total[i] = total[i] +1
}
if(j ==length(v)) break
j = j+1
}
total
[1] 1 2 1 2 2 1 0 0 0 0
I got this error(not here, in the real case):
Error in begin:end : argument of length 0
(I tried using an if in case begin = end) but "for" should work for only one position.
What can be happening??
You can use seq.int instead of : in this case. For example:
for (a in seq.int(from=3, to=3)) {
print(a)
}
[1] 3

Resources