Skip to content

Allow ! on LHS of := #4031

Description

@MichaelChirico

Related to #571, #1710, a few others about allowing NSE on LHS of :=.

Based on the example given here:

#4030 (comment)

keep = c('Species', 'Sepal.Width')
dt[ , setdiff(names(dt), keep) := NULL]
setcolorder(dt, keep)

Would be quite natural/less clumsy/available for chaining to do:

keep = c('Species', 'Sepal.Width')
dt[ , !keep := NULL] #or maybe, !(keep)
setcolorder(dt, keep)

Activity

  1. moodymudskipper commented on Nov 12, 2019

    @moodymudskipper

    I've already been confused by the use of ! in data.table and this one gave me pause too (it's not obvious that we mean "not this column" and not, "negate the values of this variable".

    I think this ambiguity can be avoided by having select helpers in the style of https://www.rdocumentation.org/packages/dplyr/versions/0.7.2/topics/select_helpers

    We would have :

    dt[ , !one_of(keep) := NULL]
    

    And then all other useful select helpers would work as well :

    dt[ , starts_with("Petal") := NULL]
    

    In tidy select those helpers return numeric indices, so to use several helpers we need to use set functions like intersect(), union() and setdiff(), I'm not sure why this design choice was made, I think logical output makes more sense and allows more compact syntax using | and &.

    So for this to work the select helpers should detect the data table context and [.data.table should allow logical indices on the lhs of := in j.

    Allowing functions on the rhs would go with this quite well, so we could do things like :

    dt[, sapply(.SD, is.factor) := as.character] # or dt[, sapply(.SD, is.factor) := as.character(.)] 
    
  2. jangorecki commented on Nov 29, 2019

    @jangorecki
    Member

    I am not sure about !keep. If names(.SD) will work in LHS then

    keep = c('Species', 'Sepal.Width')
    dt[ , setdiff(names(.SD), keep) := NULL]
    setcolorder(dt, keep)
  3. mik3y64 commented on Dec 16, 2019

    @mik3y64

    Upvoting this feature. Column selection and deletion are bread and butter of data manipulation. It is not intuitive to setdiff names of columns and then delete them. It involves two extra steps for code author and not intuitive to be read by colleagues or collaborators. It is like typing --1 (double negative signs) to get 1. I am hoping to see a direct way of selecting column using reference semantics.

    keep = c("Species", "Sepal.Width")
    dat[ , keep := KEEP]

    or a more general but less direct approach, as proposed by @MichaelChirico. This is also similar to typing --1 to get 1 but the codes are much simpler.

    dat[ , !keep := NULL]
    # or
    dat[ , -keep := NULL]
  4. ColeMiller1 commented on Dec 29, 2019

    @ColeMiller1
    Contributor

    Another route would be a helper function on j to combine .SDcols with j. Use cases:

    dt[, update.at(is.factor, as.character)]
    dt[, update.at(!keep, NULL)]
    
    dt[, delete.at(!keep)]
    
    dt[, select.at(keep)]
    dt[, select.at(keep, x+ 3)]
    
  5. MichaelChirico commented on Apr 12, 2024

    @MichaelChirico
    MemberAuthor

    With names(.SD) available on LHS of :=, this now works:

    dt[ , names(.SD) := NULL, .SDcols=!keep]

    Closing here, please open other FRs if there's still something missing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions