Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

paste0 is converting everything into character

Tags:

string

r

I have a R dataframe which contains all types of mixed datatypes e.g., Factor, int and POSIXct variables. I want to concatenate all variables and combine them without changing their format.

My end output should look like this

('a', 2 ,'2019-02-11 15:57:56')('b', 3 ,'2019-02-11 15:57:56')

While using paste0 , it is converting everything into character.. Need your help on this. Is there any other alternative apart from paste0 to combine everything and get output like above.

library(lubridate)
library(dplyr)
dat <- data.frame(id = letters[1:2], x = 2:3, date = now())
dat
str(dat)
'data.frame':   2 obs. of  3 variables:
 $ id  : Factor w/ 2 levels "a","b": 1 2
 $ x   : int  2 3
 $ date: POSIXct, format: "2019-02-11 15:57:56" "2019-02-11 15:57:56"

dat[1,]
  id x                date
1  a 2 2019-02-11 15:57:56

Currently I am using this but gave undesired results.

paste0('(',paste0(dat[1,],collapse = "','"), ')')
[1] "(1','2','1549880876.5498)"

like image 916
User1101 Avatar asked Jul 20 '26 23:07

User1101


2 Answers

I realized now what you meant - you want variables of type character to be quoted in the string, and the others not. A couple of problems - First, the way you are collapsing with ',', you are adding quotes on everything. Second, the way you are creating the dataframe is converting the dates to a double, and the letters to an integer:

> library(lubridate)
> library(dplyr)
> dat <- data.frame(id = letters[1:2], x = 2:3, date = now())
> typeof(dat$id[1])
[1] "integer"
> typeof(dat$date[1])
[1] "double"
>

so it will be hard to detect programmatically you meant these are strings. Use I to make sure characters remain as such, and use format to make sure the date is a string (It has options, but I am not using them):

> dat <- data.frame(id = I(letters[1:2]), x = 2:3, date = I(format(now())))
> dat
  id x                date
1  a 2 2019-02-11 15:01:52
2  b 3 2019-02-11 15:01:52
> typeof(dat$date[1])
[1] "character"
> typeof(dat$id[1])
[1] "character"

Now that out dataframe has the right types, let's prepare it before pasting to already quote stuff we want quoted in the end:

> as.data.frame(lapply(dat,function(x) { if (is.character(x)) paste0("'",x,"'") else x }))
   id x                  date
1 'a' 2 '2019-02-11 15:01:52'
2 'b' 3 '2019-02-11 15:01:52'

Now pasting becomes simpler - we need to collapse each row, and surround it with parenthesis, and then collapse the resulting strings. In a single line this is (after fixing dat as above):

> paste0(
    apply(
        as.data.frame(
            lapply(dat,function(x) { if (is.character(x)) paste0("'",x,"'") else x })),
        1,function(x){paste0('(',paste0(x,collapse=','),')')})
    ,collapse=',')   
 [1] "('a',2,'2019-02-11 15:01:52'),('b',3,'2019-02-11 15:01:52')"

A long line, so I broke it up a bit.

like image 84
kabanus Avatar answered Jul 23 '26 16:07

kabanus


The glue package is fantastic for these use-cases:

library(tidyverse)
library(glue)

dat <- data.frame(id = letters[1:2], x = 2:3, date = lubridate::now())

dat %>%
  mutate(
    description = glue("('{id}', {x}, '{date}')")
  )
#>   id x                date                     description
#> 1  a 2 2019-02-11 09:53:29 ('a', 2, '2019-02-11 09:53:29')
#> 2  b 3 2019-02-11 09:53:29 ('b', 3, '2019-02-11 09:53:29')

Moreover, if you want just the new description column, you could add %>% pull(description) to the pipeline to get:

(above code) %>% pull(description)

('a', 2, '2019-02-11 09:52:14')
('b', 3, '2019-02-11 09:52:14')

And then perhaps even a paste(collapse = ",") depending on what you plan to do with the output:

(above code) %>% pull(description) %>% paste(collapse = ",")

[1] "('a', 2, '2019-02-11 09:52:14'),('b', 3, '2019-02-11 09:52:14')"
like image 28
JasonAizkalns Avatar answered Jul 23 '26 16:07

JasonAizkalns



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!