We can do this using data.table . We will convert 'data.frame' to 'data.table' ( setDT(df1) ). We are grouped by 'ID', we check the length of unique elements in 'A' ( uniqueN(A) ) is greater than 1 or not, create an ind column on it. We can then split data set based on the fact that the column is "ind".
library(data.table) setDT(df1)[, ind:= uniqueN(A)>1, by = ID] setDF(df1) split(df1[-5], df1$ind)
Or in a similar way, with dplyr we can use n_distinct to create a logical column and then split on that column.
library(dplyr) df2 <- df1 %>% group_by(ID) %>% mutate(ind= n_distinct(A)>1) split(df2, df2$ind)
Or a base R with table parameter. We get the table first two columns of 'df1', i.e. 'ID' and 'A'. By double negating ( !! ) the output, we can get the value "0" in "TRUE", and all other frequencies - "FALSE". Get rowSums ('indx'). We map the ID column in 'df1' to names 'indx', use this to replace 'ID' with TRUE/FALSE and split dataset with this.
indx <- rowSums(!!table(df1[1:2]))>1 lst <- split(df1, indx[match(df1$ID, names(indx))]) lst
If we need to get separate datasets in a global environment, change the names of the list elements to the names of the objects we need and use list2env (not recommended)
list2env(setNames(lst, c('L', 'K')), envir=.GlobalEnv)
source share