R list get first item of each element - r

This should probably be very easy for someone to answer but I have had no success on finding the answer anywhere.
I am trying to return, from a list in R, the first item of each element of the list.
> a
[1] 1 2 3
> b
[1] 11 22 33
> c
[1] 111 222 333
> d <- list(a = a,b = b,c = c)
> d
$a
[1] 1 2 3
$b
[1] 11 22 33
$c
[1] 111 222 333
Based on the construction of my list d above, I want to return a vector with three values:
return 1 11 111

sapply(d, "[[", 1) should do the trick.
A bit of explanation:
sapply: iterates over the elements in the list
[[: is the subset function. So we are asking sapply to use the subset function on each list element.
1 : is an argument passed to "[["
It turns out that "[" or "[[" can be called in a traditional manner which may help to illustrate the point:
x <- 10:1
"["(x, 3)
# [1] 8

You can do
output <- sapply(d, function(x) x[1])
If you don't need the names
names(output) <- NULL

Related

Using letters in function argument

Im trying to create a function that returns characteristic symbol to a defined value like this
"a" to 1
"b" to 2
"c" to 3
And where there is only one input argument (one of "a", "b" or "c") in the function. Like this: function(x), for example function("a") returns 1.
We can convert with matching to the default Constant vector letters
f1 <- function(arg1){
match(arg1, letters)
}
f1('a')
#[1] 1
f1('b')
#[1] 2
f1(c('a', 'b', 'c'))
#[1] 1 2 3
letterToNumber <- function(x){
which(x == letters)}
sapply(letters[1:10], letterToNumber)
a b c d e f g h i j
1 2 3 4 5 6 7 8 9 10
You can create a dictionary like structure by using a named vector.
f <- function(x)
{
dict <- setNames(seq_along(letters),letters)
unname(dict[x])
}
f("a")
[1] 1
f("g")
[1] 7
f(c("a","z"))
[1] 1 26
This will be faster than other solutions but won't fail if you don't feed a lower case letter :
foo <- function(x) utf8ToInt(x) - 96L
foo("m")
#> [1] 13

Replace empty element in a list using sapply

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

Remove elements in a list in R

I want to remove part of the list where it is a complete set of the other part of the list. For example, B intersect A and E intersect C, therefore B and E should be removed.
MyList <- list(A=c(1,2,3,4,5), B=c(3,4,5), C=c(6,7,8,9), E=c(7,8))
MyList
$A
[1] 1 2 3 4 5
$B
[1] 3 4 5
$C
[1] 6 7 8 9
$E
[1] 7 8
MyListUnique <- RemoveSubElements(MyList)
MyListUnique
$A
[1] 1 2 3 4 5
$C
[1] 6 7 8 9
Any ideas ? Any know function to do it ?
As long as your data is not too huge, you can use an approach like the following:
# preparation
MyList <- MyList[order(lengths(MyList))]
idx <- vector("list", length(MyList))
# loop through list and compare with other (longer) list elements
for(i in seq_along(MyList)) {
idx[[i]] <- any(sapply(MyList[-seq_len(i)], function(x) all(MyList[[i]] %in% x)))
}
# subset the list
MyList[!unlist(idx)]
#$C
#[1] 6 7 8 9
#
#$A
#[1] 1 2 3 4 5
Similar to the other answer, but hopefully clearer, using a helper function and 2 sapplys.
#helper function to determine a proper subset - shortcuts to avoid setdiff calculation if they are equal
is.proper.subset <- function(x,y) !setequal(x,y) && length(setdiff(x,y))==0
#double loop over the list to find elements which are proper subsets of other elements
idx <- sapply(MyList, function(x) any(sapply(MyList, function(y) is.proper.subset(x,y))))
#filter out those that are proper subsets
MyList[!idx]
$A
[1] 1 2 3 4 5
$C
[1] 6 7 8 9

Naming list items via loop in R

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.

Subset a list (choose matching values for all components)

I try to read out certain elements from a list in a way, thats equivalent to df[, c(1,4,5)] in a data.frame.
> obj <- list(c(1:5), c(1:5))
> obj
[[1]]
[1] 1 2 3 4 5
[[2]]
[1] 1 2 3 4 5
Im looking for a result like this
[[1]]
[1] 1 4 5
[[2]]
[1] 1 4 5
I have been experimenting with [], [[]] and [[]][] but thats assessing the list componentwise.
I've also been trying lapply(obj, c(1,4,5)) and looking at match().
I'm not quite there yet, help would be appreciated.
Thx!
You should call lapply with a function which is run on every list entry:
obj <- list(c(1:5), c(1:5))
lapply(obj, function(x) x[c(1, 4, 5)])
#[[1]]
[1] 1 4 5
[[2]]
[1] 1 4 5
EDi has a great answer, but you can do it by passing the [ function to lapply plus additional arguments:
lapply(obj, '[', c(1, 4, 5))
You can access this and the other "weird" functions in R by quoting them:
?"["

Resources