@@ -22,6 +22,26 @@ methods::setPackageName("data.table",.global)
2222is.data.table = function (x ) inherits(x , " data.table" )
2323is.ff = function (x ) inherits(x , " ff" ) # define this in data.table so that we don't have to require(ff), but if user is using ff we'd like it to work
2424
25+ # Helper function to process assignment operations in lists or environments.
26+ # Used internally for efficient recursive assignments in data.table.
27+
28+ process_assignment <- function (name , x , parent_env ) {
29+ k = eval(name [[2L ]], parent_env , parent_env )
30+ if (is.list(k )) {
31+ origj = j = if (name [[1L ]] == " $" ) as.character(name [[3L ]]) else eval(name [[3L ]], parent_env , parent_env )
32+ if (is.character(j )) {
33+ if (length(j ) != 1L )
34+ stopf(" Cannot assign to an under-allocated recursively indexed list -- L[[i]][,:=] syntax is only valid when i is length 1, but its length is %d" , length(j ))
35+ j = match(j , names(k ))
36+ if (is.na(j ))
37+ stopf(" Item '%s' not found in names of input list" , origj )
38+ }
39+ .Call(Csetlistelt , k , as.integer(j ), x )
40+ } else if (is.environment(k ) && exists(as.character(name [[3L ]]), k )) {
41+ assign(as.character(name [[3L ]]), x , k , inherits = FALSE )
42+ }
43+ }
44+
2545# NCOL = function(x) {
2646# # copied from base, but additionally covers data.table via is.list()
2747# # because NCOL in base explicitly tests using is.data.frame()
@@ -1222,22 +1242,9 @@ replace_dot_alias = function(e) {
12221242 setalloccol(x , n , verbose = verbose ) # always assigns to calling scope; i.e. this scope
12231243 if (is.name(name )) {
12241244 assign(as.character(name ),x ,parent.frame(),inherits = TRUE )
1225- } else if (.is_simple_extraction(name )) { # TODO(#6702): use a helper here as the code is very similar to setDT().
1226- k = eval(name [[2L ]], parent.frame(), parent.frame())
1227- if (is.list(k )) {
1228- origj = j = if (name [[1L ]] == " $" ) as.character(name [[3L ]]) else eval(name [[3L ]], parent.frame(), parent.frame())
1229- if (is.character(j )) {
1230- if (length(j )!= 1L ) stopf(" Cannot assign to an under-allocated recursively indexed list -- L[[i]][,:=] syntax is only valid when i is length 1, but its length is %d" , length(j ))
1231- j = match(j , names(k ))
1232- if (is.na(j )) internal_error(" item '%s' not found in names of list" , origj ) # nocov
1233- }
1234- .Call(Csetlistelt ,k ,as.integer(j ), x )
1235- } else if (is.environment(k ) && exists(as.character(name [[3L ]]), k )) {
1236- assign(as.character(name [[3L ]]), x , k , inherits = FALSE )
1237- } else if (isS4(k )) {
1238- .Call(CsetS4elt , k , as.character(name [[3L ]]), x )
1239- }
1240- } # TO DO: else if env$<- or list$<-
1245+ } else if (name %iscall % c(' $' , ' [[' ) && is.name(name [[2L ]])) {
1246+ process_assignment(name , x , parent.frame())
1247+ }
12411248 }
12421249 }
12431250 }
@@ -2970,25 +2977,13 @@ setDT = function(x, keep.rownames=FALSE, key=NULL, check.names=FALSE) {
29702977 if (is.name(name )) {
29712978 name = as.character(name )
29722979 assign(name , x , parent.frame(), inherits = TRUE )
2973- } else if (.is_simple_extraction(name )) {
2974- # common case is call from 'lapply()'
2975- k = eval(name [[2L ]], parent.frame(), parent.frame())
2976- if (is.list(k )) {
2977- origj = j = if (name [[1L ]] == " $" ) as.character(name [[3L ]]) else eval(name [[3L ]], parent.frame(), parent.frame())
2978- if (length(j ) == 1L ) {
2979- if (is.character(j )) {
2980- j = match(j , names(k ))
2981- if (is.na(j ))
2982- stopf(" Item '%s' not found in names of input list" , origj )
2983- }
2984- }
2985- .Call(Csetlistelt , k , as.integer(j ), x )
2986- } else if (is.environment(k ) && exists(as.character(name [[3L ]]), k )) {
2987- assign(as.character(name [[3L ]]), x , k , inherits = FALSE )
2988- } else if (isS4(k )) {
2980+ } else if (name %iscall % c(' $' , ' [[' ) && is.name(name [[2L ]])) {
2981+ process_assignment(name , x , parent.frame())
2982+ }
2983+ else if (isS4(k )) {
29892984 .Call(CsetS4elt , k , as.character(name [[3L ]]), x )
29902985 }
2991- } else if (name %iscall % " get" ) { # #6725
2986+ else if (name %iscall % " get" ) { # #6725
29922987 # edit 'get(nm, env)' call to be 'assign(nm, x, envir=env)'
29932988 name = match.call(get , name )
29942989 name [[1L ]] = quote(assign )
0 commit comments