StatsSorceress
StatsSorceress

Reputation: 3109

R: create a vector based on a list

I have the following list called m1:

> m1
[[1]]
[1] 36 37 38

[[2]]
[1] 34 35

[[3]]
[1] 30 31 32 33

[[4]]
[1] 24 25 26 27 28 29

[[5]]
[1] 20 21 22 23

[[6]]
[1] 14 15 16 17 18 19

[[7]]
[1] 11 12 13

[[8]]
[1]  7  8  9 10

[[9]]
[1] 5 6

[[10]]
[1] 1 2 3 4

[[11]]
integer(0)

I would like to create a vector based on this list, which has the value 1 at positions 36, 37, and 38; the value 2 at positions 34 and 35, etc. The final output should be:

vector_1 <- c(10, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 1, 1, 1)

How can I accomplish this in R?

EDIT:

Thanks to a comment below:

> rep(length(m1):1, sapply(m1, length))
 [1] 11 11 11 10 10  9  9  9  9  8  8  8  8  8  8  7  7  7  7  6  6  6  6  6  6  5  5  5  4
[30]  4  4  4  3  3  2  2  2  2

That doesn't quite give me what I want, but it's definitely on the right track!

Upvotes: 3

Views: 68

Answers (4)

www
www

Reputation: 4224

Try this:

rev(unlist(sapply(1:length(m1), function(x) rep(x,length(m1[[x]])))))

#or even better, @snoram's edited version of this:

rev(rep(seq_along(m1), sapply(m1, length)))

Output:

[1] 10 10 10 10  9  9  8  8  8  8  7  7  7  6  6  6  6  6  6  5  5  5  5  4
[25]  4  4  4  4  4  3  3  3  3  2  2  1  1  1

Sample data:

m1 <- list(36:38,34:35,30:33,24:29,20:23,
           14:19,11:13,7:10,5:6,1:4)
names(m1) <- 1:10

Upvotes: 1

s_baldur
s_baldur

Reputation: 33603

Here is a straightforward base-R solution:

# data
m1 <- list(36:38, 34:35, 30:33, 24:29, 20:23, 14:19, 11:13, 7:10, 5:6, 1:4, integer(0))

# Count length, and repeat each number in 1:11 accordingly
rev(rep(1:11, sapply(m1, length)))
 [1] 10 10 10 10  9  9  8  8  8  8  7  7  7  6  6  6  6  6  6  5  5  5  5  4  4  4  4  4  4  3  3  3
[33]  3  2  2  1  1  1

Edit: A more generalisable answer would be:

rev(rep(seq_along(m1), sapply(m1, length)))

Upvotes: 2

emilliman5
emilliman5

Reputation: 5966

This should handle cases with empty entries and non-sequential entries....

m1 <- list(c(7,4,5), c(2,10,9), c(1,3,6,8), integer())
# [[1]]
# [1] 7 4 5
# 
# [[2]]
# [1]  2 10  9
# 
# [[3]]
# [1] 1 3 6 8
# 
# [[4]]
# integer(0)

rep(seq_along(m1), sapply(m1, length))[order(unlist(m1))]
#[1] 3 2 3 1 1 3 1 3 2 2

Upvotes: 3

d.b
d.b

Reputation: 32558

This solution should work for more general cases too even if the elements inside m1 are not in a specific order

#DATA
m1 = list(36:38, 34:35, 30:33, 24:29, 20:23,
          14:19, 11:13, 7:10, 5:6, 1:4, integer(0))

#Extract the maximum element in m1
mymax = max(unlist(m1))
#Go through m1 using index and replace respective indices in the position
#defined by the elements of m1, otherwise make the elements zero 
Reduce("+", lapply(1:length(m1), function(i)
    replace(rep(0, mymax), m1[[i]], i)))
# [1] 10 10 10 10  9  9  8  8  8  8  7  7  7  6  6  6  6  6  6  5  5  5  5
#[24]  4  4  4  4  4  4  3  3  3  3  2  2  1  1  1

Upvotes: 2

Related Questions