Subset different vector elements within a list - r

Assume I have this list of vectors:
mylist <- list(a=1:3,b=4:1,c=1:5)
mylist
$a
[1] 1 2 3
$b
[1] 4 3 2 1
$c
[1] 1 2 3 4 5
I want to get the last or the max element of each vector like this for the last element:
$a
[1] 3
$b
[1] 1
$c
[1] 5
What I have tried so far:
First use lapply and the length function to get the last element index and then subset:
last <- unlist(lapply(mylist, length))
lapply(mylist,"[", last) # not working
Then I tried to use sapply with lapply. This is working, but I'm not sure whether this is generally valid. There must be a better base R solution (without loops!).
mymatrix <- sapply(last, function(x) lapply(mylist, "[",x))
diag(mymatrix)
$a
[1] 3
$b
[1] 1
$c
[1] 5

(Making this a CV as there were many contributes here and worth summing this up)
If you have some function you want to apply on your list, a simple lapply should do, such as
lapply(mylist, max) # retrieving the maximum values
Or
lapply(mylist, tail, 1) # retrieving the last values (by #docendo)
If you want to operate on two vectors simultaneously, you could use mapply or Map
Map(`[`, mylist, lengths(mylist)) # A Map version of #docendos lapply suggestion
Or per your newest request
Map(`[`, mylist, 1:3)

Related

Merging two lists with similar elements in R [duplicate]

I have two lists with named elements:
a <- list(a=1, b=2)
b <- list(b=3, c=4)
I want to combine these lists, so that any elements in a that have the same names will be overwritten by the list b, so I get this out:
list(a=1, b=3, c=4)
I know I could do this in a loop, but is there a more compact way of doing this in R?
R has a built in function to do that modifyList
modifyList(a, b)
Here's a simple solution:
# create new list
newlist <- c(a,b)
# remove list element(s)
newlist[!duplicated(names(newlist), fromLast = TRUE)]
The result:
$a
[1] 1
$b
[1] 3
$c
[1] 4
An even simpler solution with setdiff:
c(a[setdiff(names(a), names(b))], b)
$a
[1] 1
$b
[1] 3
$c
[1] 4

Weird behavior when trying to sort vectors in a list using a loop

I want to sort vectors in a list. I tried the following:
test <- list(c(2,3,1), c(3,2,1), c(1,2,3))
for (i in length(test)){
test[[i]] <- sort(test[[i]])
}
test
Which returns the list unchanged (vectors not sorted):
[[1]]
[1] 2 3 1
[[2]]
[1] 3 2 1
[[3]]
[1] 1 2 3
However when I sort manually outside the loop the order is stored:
test[[1]]
[1] 2 3 1
test[[1]] <- sort(test[[1]])
test[[1]]
[1] 1 2 3
Why does the behaviour in the loop differ? I would expect the loop to store three vectors c(1,2,3) in the list. What am I missing?
I just figured the loop only loops over one element since length(test) = 3. Hence I should have used for (i in 1:length(test)).

Subset list of vectors with vector of positions

I have a list of vectors (mylist):
a <- c(1,2,3,4)
b <- c(5,6,7,8)
c <- c(9,10,11,12)
mylist <- list(a,b,c)
I also have a vector of positions (mypos):
mypos <- c(1,2,3)
I would like to use mypos to give the position of elements to subset each vector of mypos so that it returns:
[1] 1 6 11
I have tried using lapply like this:
lapply(mylist, "[", mypos)
but this returns elements 1, 2 and 3 of each vector:
[[1]]
[1] 1 2 3
[[2]]
[1] 5 6 7
[[3]]
[1] 9 10 11
I have also tried:
lapply(mylist, subset, mypos)
But this returns an error that the subset must be logical
We can use Map to extract the corresponding elements of 'mylist' from the index of 'mypos'
Map(`[`, mylist, mypos)
In the OP's code, the 'mypos' is repeated in each of list elements resulting in extracting all the elements from the index. Instead it could be looped on sequence
lapply(seq_along(mylist), function(x) mylist[[x]][mypos[[x]]])

Using apply() over a list

I have a list with 100 vectors indexed by:
[[1]]
[1]
[[2]]
[1]
[[3]]
[1]
.
.
.
[[100]]
[1]
Each vector has 3 entries.
I would like to apply a function separately for each of the vectors. The function returns a single number for each vector so the result of the apply() would be a 100 element vector.
How can this be done using apply?
I know I can use apply for matrices by indexing 1 or 2 depending on row or column but can it also be used for lists?
You are looking for sapply:
l <- list(1:3, 2:4, 5:7)
sapply(l, sum)
# [1] 6 9 18
This answer might help you in the future.

Combine lists while overriding values with same name in R

I have two lists with named elements:
a <- list(a=1, b=2)
b <- list(b=3, c=4)
I want to combine these lists, so that any elements in a that have the same names will be overwritten by the list b, so I get this out:
list(a=1, b=3, c=4)
I know I could do this in a loop, but is there a more compact way of doing this in R?
R has a built in function to do that modifyList
modifyList(a, b)
Here's a simple solution:
# create new list
newlist <- c(a,b)
# remove list element(s)
newlist[!duplicated(names(newlist), fromLast = TRUE)]
The result:
$a
[1] 1
$b
[1] 3
$c
[1] 4
An even simpler solution with setdiff:
c(a[setdiff(names(a), names(b))], b)
$a
[1] 1
$b
[1] 3
$c
[1] 4

Resources