15

I have been breaking my head over translating this question to a data.table solution. (to keep it simple I'll use the same data set)
When V2 == "b I want to swap the columns between V1 <-> V3.

dt <- data.table(V1=c(1,2,4), V2=c("a","a","b"), V3=c(2,3,1))
#V1 V2 V3
#1:  1  a  2
#2:  2  a  3
#3:  4  b  1

The code below would be the working solution for data.frame, however because of the amount of frustration this has given me because I was using a data.table without realising I'm now determined to find a solution for data.table.

dt <- data.table(V1=c(1,2,4), V2=c("a","a","b"), V3=c(2,3,1))
df <- as.data.frame(dt)
df[df$V2 == "b", c("V1", "V3")] <- df[df$V2 == "b", c("V3", "V1")] 
#  V1 V2 V3
#1  1  a  2
#2  2  a  3
#3  1  b  4

I have tried writing a lapply function looping through my target swapping list, tried to narrow down the problem to only replace one value, attempted to call the column names in different ways but all without success.
This was the closest attempt I've managed to get:

> dt[dt$V2 == "b", c("V1", "V3")] <- dt[dt$V2 == "b", c(V3, V1)]
#Warning messages:
#1: In `[<-.data.table`(`*tmp*`, dt$V2 == "b", c("V1", "V3"), value = c(1,  :
#  Supplied 2 items to be assigned to 1 items of column 'V1' (1 unused)
#2: In `[<-.data.table`(`*tmp*`, dt$V2 == "b", c("V1", "V3"), value = c(1,  :
#  Supplied 2 items to be assigned to 1 items of column 'V3' (1 unused)

How can we get the data.table solution?

Community
  • 1
  • 1
Bas
  • 1,066
  • 1
  • 10
  • 28

2 Answers2

17

We can try

dt[V2=="b", c("V3", "V1") := .(V1, V3)]
eddi
  • 49,088
  • 6
  • 104
  • 155
akrun
  • 874,273
  • 37
  • 540
  • 662
  • I guess using `.SD` is faster than passing `list(V1, V3)`? – BenBarnes Apr 25 '16 at 06:53
  • 1
    @BenBarnes I didn't test whether it will be faster, looks like `list(V1, V3)` would be fine too. – akrun Apr 25 '16 at 07:07
  • @eddi, what you have against `.SDcols`? I think it is more robust solution in case you have a vector of predefined columns. – David Arenburg Apr 25 '16 at 16:11
  • 1
    @DavidArenburg that's a strange question :) I have nothing against `.SDcols` when it's used appropriately. In this case all it did was add extra symbols to type and make the solution more opaque. – eddi Apr 25 '16 at 16:14
2

For amusement only. @akruns' solution is clearly superior. I reasoned that I could create a temporary copy, make the conditional swap, and then delete the copy all using [.data.table operations in sequence:

 dt[, tv1 := V1][V2=="b", V1 := V3][V2=="b", V3 := tv1][ , tv1 := NULL]

> dt
   V1 V2 V3
1:  1  a  2
2:  2  a  3
3:  1  b  4
IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • 5
    Ah, yes, I was swapping the "a" values instead of the "b" values. Seems hardly worth fixing since it's going to be so slow. I only posted it so people could throw tomatoes. – IRTFM Apr 25 '16 at 07:10
  • at least do a `bitwXor` solution if you're aiming for amusing; not amused as-is – eddi Apr 25 '16 at 15:51
  • I wish I knew what a `bitwXor` was. Guess I will need to do some searching. – IRTFM Apr 25 '16 at 17:00