rdataframe

Better methods to identify and swap two values within a variable


I'm looking for a more efficient way to swap two values within a variable. In the dataframe, each respondent has a unique id.

set.seed(1234)

test <- data.frame(
  id = sample(1:10),
  value = 21:30
)

test
   id value
1  10    21
2   6    22
3   5    23
4   4    24
5   1    25
6   8    26
7   2    27
8   7    28
9   9    29
10  3    30

Assume id 6 and 3 are misplaced; 6 should be in row 10 and 3 should be in row 2.

Note that the sequence of id is not fixed. (The seed here is only for replication.) I always use a temp id to address this issue.

test$id[test$id == 6] <- 999 # Not a real id
test$id[test$id == 3] <- 6
test$id[test$id == 999] <- 3

   id value
1  10    21
2   3    22
3   5    23
4   4    24
5   1    25
6   8    26
7   2    27
8   7    28
9   9    29
10  6    30

I know match or grep can accomplish this as well.

pos_six <- match(6, test$id)
test$id[match(3, test$id)] <- 6
test$id[pos_six] <- 3

   id value
1  10    21
2   3    22
3   5    23
4   4    24
5   1    25
6   8    26
7   2    27
8   7    28
9   9    29
10  6    30

It is not challenging. However, I am still interested in exploring different, more elegant approaches.


Update:

I am seeking answers to fulfill one of the following:

  1. Shorter code: reduce 3 lines to 2 or even 1.
  2. Simplified workflow: above examples reassign values one by one, it would be great to finish this at the same time.
  3. Different approach: without the usage of index. Not sure if it is possible, but would enjoyable to learn.

Solution

  • You can swap values with foo[c(i, j)] <- foo[c(j, i)], e.g.

    test <- data.frame(id = 10:1, value = 21:30)
    
    idx <- match(c(3, 6), test$id); 
    within(test, id[idx] <- id[rev(idx)])
    #>    id value
    #> 1  10    21
    #> 2   9    22
    #> 3   8    23
    #> 4   7    24
    #> 5   3    25
    #> 6   5    26
    #> 7   4    27
    #> 8   6    28
    #> 9   2    29
    #> 10  1    30
    

    Created on 2025-01-21 with reprex v2.1.1