Aggiunta di nuove colonne a un riferimento per data.table all’interno di una funzione non sempre funzionante

Nello scrivere un pacchetto che si basa su data.table , ho scoperto alcuni comportamenti strani. Ho una funzione che rimuove e riordina alcune colonne per riferimento, e funziona perfettamente, il che significa che data.table I passato è stato modificato senza assegnare l’output della funzione. Ho un’altra funzione che aggiunge nuove colonne, ma quelle modifiche non sempre persistono nel data.table che è stato passato.

Ecco un piccolo esempio:

 library(data.table) # I'm using 1.9.4 test <- data.table(id = letters[1:2], val=1:2) foobar <- function(dt, col) { dt[, (col) := 1] invisible(dt) } test # id val #1: a 1 #2: b 2 saveRDS(test, "test.rds") test2 <- readRDS("test.rds") all.equal(test, test2) #[1] TRUE foobar(test, "new") test # id val new #1: a 1 1 #2: b 2 1 foobar(test2, "new") test2 # id val #1: a 1 #2: b 2 

Quello che è successo? Cosa c’è di diverso in test2 ? Posso modificare le colonne esistenti sul posto su entrambi:

 foobar(test, "val") test # id val new #1: a 1 1 #2: b 1 1 foobar(test2, "val") test2 # id val #1: a 1 #2: b 1 

Ma l’aggiunta a test2 continua a non funzionare:

 foobar(test2, "someothercol") .Last.value # id val someothercol #1: a 1 1 #2: b 1 1 test2 # id val #1: a 1 #2: b 1 

Non riesco a definire tutti i casi in cui vedo questo comportamento, ma il salvataggio e la lettura da RDS è il primo caso che riesco a replicare in modo affidabile. Scrivere e leggere da un CSV non sembra avere lo stesso problema.

Si tratta di un problema con il puntatore a questo problema , come serializzare un data.table distrugge i puntatori sovra allocati? C’è un modo semplice per ripristinarli? Come potrei controllarli all’interno della mia funzione, così potrei ripristinare i puntatori o l’errore se l’operazione non sta andando a lavorare?

So che posso assegnare l’output della funzione come soluzione, ma non è molto data.table -y. Non creerebbe anche una copia temporanea in memoria?

Risposta alla soluzione di Arun

Arun ha truelength che si tratta davvero di un problema di puntatore, che può essere diagnosticato con truelength e risolto con setDT o alloc.col . Mi sono imbattuto in un problema che incapsulava la sua soluzione in una funzione (continuando dal codice precedente):

 func <- function(dt) {if (!truelength(dt)) setDT(dt)} func2 <- function(dt) {if (!truelength(dt)) alloc.col(dt)} test2 <- readRDS("test.rds") truelength(test2) #[1] 0 truelength(func(test2)) #[1] 100 truelength(test2) #[1] 0 truelength(func2(test2)) #[1] 100 truelength(test2) #[1] 0 

Quindi sembra che la copia locale all’interno della funzione sia stata opportunamente modificata, ma la versione di riferimento non lo è. Perchè no?