简体   繁体   中英

Create a matrix using the common information in two lists

I have two large lists in the same structure of the toy examples shown in this question.

dput(head(list1)):

list(FEB_GAMES = c(GAME1 = c("Stan", "Kenny", "Cartman", "Kyle", 
"Butters"), GAME2 = c("Kenny", "Cartman", "Kyle", "Butters")), 
MAR_GAMES = c(GAME3 = c("Stan", "Kenny", "Cartman", "Butters"
), GAME4 = c("Kenny", "Cartman", "Kyle", "Butters")))

dput(head(list2)):

list(first = c("Stan", "Kenny", "Cartman", "Kyle", "Butters", 
"Kenny", "Cartman", "Kyle", "Butters"), second = c("Stan", "Kenny", 
"Cartman", "Wendy", "Ike"), third = c("Randy", "Randy", "Randy", 
"Randy"))

I would like to turn these two lists into one large data.frame/ matrix. The rownames would be from list1 (GAME1, GAME2, GAME3, GAME4). The colnames would be the list names of list 2 (first, second, third). The information in the matrix would be an integer which refers to the number of times a common character is found in both list. eg GAME1xfirst contains 9 common characters, while GAME1xthird contains 0.


The output would look like this:

        first  second  third
GAME1   9      3       0
GAME2   8      2       0
GAME3   8      3       0
GAME4   8      2       0

So the values in [1,1] would be the sum of the times a common character is found in both the GAME1 list from list 1 and the first list found in list2.

Note. Lists in both list 1 and list 2 have varying numbers of values.

An option would be to first flatten out the 'list1', do a merge after converting to data.frame and then do the table

list1a <- do.call(c, list1)
names(list1a) <- sub(".*\\.", "", names(list1a))
out <- table(merge(stack(list1a), stack(list2), by = 'values')[-1])
names(dimnames(out)) <- NULL
out
#      first second third
#GAME1     9      3     0
#GAME2     8      2     0
#GAME3     7      3     0
#GAME4     8      2     0

We can also do this in tidyverse using the same logic

library(tidyverse)
list1 %>% 
    flatten %>% 
    enframe %>% 
    unnest %>% 
    full_join(list2 %>% 
                enframe %>%
                unnest, by = 'value') %>% 
    select(-value) %>% 
    count(name.x, name.y) %>% 
    spread(name.y, n, fill = 0) %>%
    filter(!is.na(name.x))
# A tibble: 4 x 4   
#  name.x first second third
#  <chr>  <dbl>  <dbl> <dbl>
#1 GAME1      9      3     0
#2 GAME2      8      2     0
#3 GAME3      7      3     0
#4 GAME4      8      2     0

data

list1 <- list(FEB_games = list(GAME1 = c("Stan", "Kenny", "Cartman", "Kyle", 
"Butters"), GAME2 = c("Kenny", "Cartman", "Kyle", "Butters")), 
MAR_games = list(GAME3 = c("Stan", "Kenny", "Cartman", "Butters"
), GAME4 = c("Kenny", "Cartman", "Kyle", "Butters")))

list2 <- list(first = c("Stan", "Kenny", "Cartman", "Kyle", "Butters", 
 "Kenny", "Cartman", "Kyle", "Butters"), second = c("Stan", "Kenny", 
 "Cartman", "Wendy", "Ike"), third = c("Randy", "Randy", "Randy", 
"Randy"))

How about ...

sapply(l2, function(x) {
  sapply(unlist(l1, recursive = FALSE), function(y) sum(x %in% y))
})
#                 first second third
# FEB_games.GAME1     9      3     0
# FEB_games.GAME2     8      2     0
# MAR_games.GAME3     7      3     0
# MAR_games.GAME4     8      2     0

Might not be not the most efficient approach, though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM