I want to take a list, create a String vector of the names of the list items, filling in blanks with a generic name and then set the names vector as the names of the list.
My code works fine for list who dont have items with names in it. It however does nothing, when there are items with a name in it.
addNamesToList <- function(myList){
listNames <- vector()
for(i in 1:length(myList)){
if(identical(names(myList[i]),NULL)){
listNames <- c(listNames,paste("item",i,sep=""))
}else{
listNames <- c(listNames,names(myList[i]))
}
}
names(myList) <- listNames
return (myList)
}
result without named items
$item1
[1] 2 3 4
$item2
[1] "hey" "ho"
result with named items
[[1]]
[1] 2 3 4
[[2]]
[1] "hey" "ho"
$hello
[1] 2 3 4
Hope you can help.
It sounds like you want to insert names where there is not currently a name. If that's the case, I would suggest using direct assignment via names(x) <- value, instead of using a loop to fill in the blanks.
In the following example, lst creates a sample list of three elements, the second of which is not named. Notice that even if only one of the list element has a name, its names vector is a character vector the same length as lst.
( lst <- list(item1 = 1:5, 6:10, item3 = 11:15) )
# $item1
# [1] 1 2 3 4 5
#
# [[2]]
# [1] 6 7 8 9 10
#
# $item3
# [1] 11 12 13 14 15
names(lst)
# [1] "item1" "" "item3"
We can insert a name into the empty name element with the following. This will also work with a vector, provided the right side vector is the same length as the left side vector.
names(lst)[2] <- "item2"
lst
# $item1
# [1] 1 2 3 4 5
#
# $item2
# [1] 6 7 8 9 10
#
# $item3
# [1] 11 12 13 14 15
For a longer list containing sporadic empty names, you can use
names(list)[!nzchar(names(list))] <- namesToAdd
nzchar basically means "non-zero character" and returns a logical, TRUE if the element is a non-zero length string.
Related
I have a list of 4 lists with the same name:
lst1 <-
list(list(c(1,2,3)),list(c(7,8,9)),list(c(4,5,6)),list(c(10,11,12)))
names(lst1) <- c("a","b","a","b")
I want to combine the sub lists together (first "a" with second "a", first "b" with second "b":
result <- list(list(c(1,2,3,4,5,6)),list(c(7,8,9,10,11,12)))
names(result) <- c("a","b")
I have tried multiple things, but can't figure it out.
Since lst1["a"] isn't going to give us all the elements of lst1 named a, we are going to need to work with names(lst1). One base R approach would be
nm <- names(lst1)
result <- lapply(unique(nm), function(n) unname(unlist(lst1[nm %in% n])))
names(result) <- unique(nm)
result
# $a
# [1] 1 2 3 4 5 6
#
# $b
# [1] 7 8 9 10 11 12
Another option is to use unlist first and then split the resulting vector.
vec <- unlist(lst1)
split(unname(vec), sub("\\d+$", "", names(vec)))
#$a
#[1] 1 2 3 4 5 6
#$b
#[1] 7 8 9 10 11 12
Just group the elements with the same name and unlist them:
tapply(lst1,names(lst1),FUN=function(x) unname(unlist(x)))
I'm generating pairs of objects from a vector, and there may be a triplet if the vector is of odd length. How can I store these and keep them as pairs/triplets? The pairs are vectors. I've tried adding to a vector like
vect <- c(vect, pair)
but it flattens all the pairs in the vector. I also tried appending to a list with list <- list(list, pair) and list <- list(list, list(pair)), as well as list.append() from rlist but none of that seems to work well.
You can do this with split you just need to give it a vector that says how you want to split the array.
ARRAY = 1:13
SF = rep(1:(length(ARRAY)/2), each=2)
if(length(SF) < length(ARRAY)) { SF = c(SF, SF[length(SF)]) }
split(ARRAY, SF)
$`1`
[1] 1 2
$`2`
[1] 3 4
$`3`
[1] 5 6
$`4`
[1] 7 8
$`5`
[1] 9 10
$`6`
[1] 11 12 13
I have two lists. The first one has an empty element. I'd like to replace that empty element with the first vector of the third list element of another list.
l1 <- list(a=1:3,b=4:9,c="")
l2 <- list(aa=11:13,bb=14:19,cc=data.frame(matrix(100:103,ncol=2)))
l1[sapply(l1, `[[`, 1)==""] <- l2[[3]][[1]]
Using sapply, I can identify which elements are empty. However, when I try to assign a vector to this empty element: I get this error message:
Warning message: In l1[sapply(l1, [[, 1) == ""] <- l2[[3]][[1]] :
number of items to replace is not a multiple of replacement length
This is only a warning, but the result I get is not the one I want. This is the l1 I get:
> l1
$a
[1] 1 2 3
$b
[1] 4 5 6 7 8 9
$c
[1] 100
This is what I need (two elements in $c):
> l1
$a
[1] 1 2 3
$b
[1] 4 5 6 7 8 9
$c
[1] 100 101
Just use l2[[3]][1] on the right hand side (single [ not [[)
The right-hand side should be a list, since you're replacing a list element. So you want that to be
... <- list(l2[[3]][[1]])
In addition, you might consider using !nzchar(l1) in place of sapply(...) == "". It might be more efficient. The final expression would be:
l1[!nzchar(l1)] <- list(l2[[3]][[1]])
giving the updated l1:
$a
[1] 1 2 3
$b
[1] 4 5 6 7 8 9
$c
[1] 100 101
I like to report a specific column from every dataframe from a list of dataframes. Any ideas? This is my code:
# Create dissimilarity matrix
df.diss<-dist(t(df[,6:11]))
mds.table<-list() # empty list of values
for(i in 1:6){ # For Loop to iterate over a command in a function
a<-mds(pk.diss,ndim=i, type="ratio", verbose=TRUE,itmax=1000)
mds.table[[i]]<-a # Store output in empty list
}
Now here is where I'm having trouble. After storing the values, I'm unable to call a specific column from every dataframe from the list.
# This function should call every $stress column from each data frame.
lapply(mds.table, function(x){
mds.table[[x]]$stress
})
Thanks again!
you are very close:
set.seed(1)
l_df <- lapply(1:5, function(x){
data.frame(a = sample(1:5,5), b = sample(1:5,5))
})
lapply(l_df, function(x){
x[['a']]
})
[[1]]
[1] 2 5 4 3 1
[[2]]
[1] 2 1 3 4 5
[[3]]
[1] 5 1 2 4 3
[[4]]
[1] 3 5 2 1 4
[[5]]
[1] 5 3 4 2 1
I have a vector of integers like this:
a <- c(2,3,4,1,2,1,3,5,6,3,2)
values<-c(1,2,3,4,5,6)
I want to list, for every unique value in my vector (the unique values being ordered), the position of their occurences. My desired output:
rep_indx<-data.frame(c(4,6),c(1,5,11),c(2,7,10),c(3),c(8),c(9))
split fits pretty well here, which returns a list of indexes for each unique value in a:
indList <- split(seq_along(a), a)
indList
# $`1`
# [1] 4 6
#
# $`2`
# [1] 1 5 11
#
# $`3`
# [1] 2 7 10
#
# $`4`
# [1] 3
#
# $`5`
# [1] 8
#
# $`6`
# [1] 9
And you can access the index by passing the value as a character, i.e.:
indList[["1"]]
# [1] 4 6
You can do this, using sapply. The ordering that you need is ensured by the sort function.
sapply(sort(unique(a)), function(x) which(a %in% x))
#### [[1]]
#### [1] 4 6
####
#### [[2]]
#### [1] 1 5 11
#### ...
It will result in a list, giving the indices of your repetitions. It can't be a data.frame because a data.frame needs to have columns of same lengths.
sort(unique(a)) is exactly your vector variable.
NOTE: you can also use lapply to force the output to be a list. With sapply, you get a list except if by chance the number of replicates is always the same, then the output will be a matrix... so, your choice!
Perhaps this also works
order(match(a, values))
#[1] 4 6 1 5 11 2 7 10 3 8 9
You can use the lapply function to return a list with the indexes.
lapply(values, function (x) which(a == x))