How to Create a List in R from Two Vectors (One Would Be the Keys, the Other the Values)

how to create a list in R from two vectors (one would be the keys, the other the values)?

If your values are all scalars, then there's nothing wrong with having a "key-value store" that's just a vector.

vals <- 1:1000000
keys <- paste0("key", 1:1000000)
names(vals) <- keys

You can then retrieve the value corresponding to a given key with

vals["key42"]
[1] 42

IIRC R uses hashing for character-based indexing, so lookups should be fast regardless of the size of your vector.

If your values can be arbitrary objects, then you do need a list.

vals <- list(1:100, lm(speed ~ dist, data=cars), function(x) x^2)
names(vals) <- c("numbers", "model", "function")

sq <- vals[["function"]]
sq(5)
[1] 25

If your question is about constructing the list, I wouldn't be too worried. R internally is copy-on-write (objects are only copied if their contents are modified), so doing something like

vals <- list(1:1000000, 1:1000000, <other big objects>)

will not actually make extra copies of everything.

Edit: I just checked, and R will copy everything if you do lst <- list(....). Go figure. So if you're already close to the memory limit on your machine, this won't work. On the other hand, if you do names(lst) <- ...., it won't make another copy of lst. Go figure again.

Creating a named list from two vectors (names, values)

You can use setNames()

setNames(as.list(c(1, 2)), c("foo", "bar"))

(for a list) or

setNames(c(1, 2), c("foo", "bar"))

(for a vector)

R: Vector of keys and vector of values to list

We can perform the operation in a single line with base R

as.list(setNames(values, keys))

#$key1
#[1] 1

#$key2
#[1] 2

#$key3
#[1] 3

Invert a list of (key, values) pairs

We may use stack with split in base R

with(stack(key_values_list), split(as.character(ind), values))

If the order needs to be maintained

with(stack(key_values_list), split(as.character(ind),
factor(values, levels = unique(values))))

Or with rep/lengths/unlist

setNames(as.list(rep(names(key_values_list), 
lengths(key_values_list))), unlist(key_values_list))

match names between vectors and assign corresponding values

a[intersect(names(b), names(a))] <- b[intersect(names(b), names(a))]
> a
1 2 3 4 5 6 7 8 9 10
"e" NA NA NA "u" "n" NA NA "g" "j"

How to correctly use lists?

Just to address the last part of your question, since that really points out the difference between a list and vector in R:

Why do these two expressions not return the same result?

x = list(1, 2, 3, 4); x2 = list(1:4)

A list can contain any other class as each element. So you can have a list where the first element is a character vector, the second is a data frame, etc. In this case, you have created two different lists. x has four vectors, each of length 1. x2 has 1 vector of length 4:

> length(x[[1]])
[1] 1
> length(x2[[1]])
[1] 4

So these are completely different lists.

R lists are very much like a hash map data structure in that each index value can be associated with any object. Here's a simple example of a list that contains 3 different classes (including a function):

> complicated.list <- list("a"=1:4, "b"=1:3, "c"=matrix(1:4, nrow=2), "d"=search)
> lapply(complicated.list, class)
$a
[1] "integer"
$b
[1] "integer"
$c
[1] "matrix"
$d
[1] "function"

Given that the last element is the search function, I can call it like so:

> complicated.list[["d"]]()
[1] ".GlobalEnv" ...

As a final comment on this: it should be noted that a data.frame is really a list (from the data.frame documentation):

A data frame is a list of variables of the same number of rows with unique row names, given class ‘"data.frame"’

That's why columns in a data.frame can have different data types, while columns in a matrix cannot. As an example, here I try to create a matrix with numbers and characters:

> a <- 1:4
> class(a)
[1] "integer"
> b <- c("a","b","c","d")
> d <- cbind(a, b)
> d
a b
[1,] "1" "a"
[2,] "2" "b"
[3,] "3" "c"
[4,] "4" "d"
> class(d[,1])
[1] "character"

Note how I cannot change the data type in the first column to numeric because the second column has characters:

> d[,1] <- as.numeric(d[,1])
> class(d[,1])
[1] "character"

How to add variable key/value pair to list object?

R lists can be thought of as hashes- vectors of objects that can be accessed by name. Using this approach you can add a new entry to the list like so:

key <- "width"
value <- 32

mylist <- list()
mylist[[ key ]] <- value

Here we use the string stored in the variable key to access a position in the list much like using the value stored in a loop variable i to access a vector through:

vector[ i ]

The result is:

myList
$width
[1] 32

R + combine a list of vectors into a single vector

A solution that is faster than the one proposed above:

vec<-unlist(lst)
vec[which(c(1,diff(vec)) != 0)]

Convert named list to vector with values only

Use unlist with use.names = FALSE argument.

unlist(myList, use.names=FALSE)

How do I make a list of data frames?

This isn't related to your question, but you want to use = and not <- within the function call. If you use <-, you'll end up creating variables y1 and y2 in whatever environment you're working in:

d1 <- data.frame(y1 <- c(1, 2, 3), y2 <- c(4, 5, 6))
y1
# [1] 1 2 3
y2
# [1] 4 5 6

This won't have the seemingly desired effect of creating column names in the data frame:

d1
# y1....c.1..2..3. y2....c.4..5..6.
# 1 1 4
# 2 2 5
# 3 3 6

The = operator, on the other hand, will associate your vectors with arguments to data.frame.

As for your question, making a list of data frames is easy:

d1 <- data.frame(y1 = c(1, 2, 3), y2 = c(4, 5, 6))
d2 <- data.frame(y1 = c(3, 2, 1), y2 = c(6, 5, 4))
my.list <- list(d1, d2)

You access the data frames just like you would access any other list element:

my.list[[1]]
# y1 y2
# 1 1 4
# 2 2 5
# 3 3 6


Related Topics



Leave a reply



Submit