R Paste multiple - r

I am currently taking in multiple command line parameters within my R script such as :
args<-commandArgs(TRUE)
arg1 <- as.numeric(args[1])
arg2 <- as.numeric(args[2])
I am wanting to use these args within my paste string like below. My problem is that I can only figure out how to use 1 of the arguments and not both (arg1, arg2). Instead of "xxx" that I show below in my where clause (i.e. "columnname1 in (xxx)") how do I use the "arg1" command line parameter in place of "xxx"? I've tried a number of different ways and for some reason I can't figure it out. Should I concatenate two different strings to accomplish this or is there an easier way?
SQL<-paste(
"SELECT
*
FROM
table
WHERE
columnname1 in (xxx)
and
columnname2 in ('",arg2,"')",sep = "")
Thanks for your help!

Try:
SQL<-paste(
"SELECT
*
FROM
table
WHERE
columnname1 in ('",arg1,"')
and
columnname2 in ('",arg2,"')",sep = "", collapse="")

You could also use the following helper function that allows named substitutions:
SQL<-strsubst(
"SELECT * FROM table WHERE
columnname1 in ('$(arg1)') and
columnname2 in ('$(arg2)')",
list(arg1=arg1, arg2=arg2)
)
where strsubst is defined as follows:
strsubst <- function (template, map, verbose = getOption("verbose"))
{
pat <- "\\$\\([^\\)]+\\)"
res <- template
map <- unlist(map)
m <- gregexpr(pat, template)
idx <- which(sapply(m, function(x) x[[1]] != -1))
for (i in idx) {
line <- template[[i]]
if (verbose)
cat("input: |", template[[i]], "|\n")
starts <- m[[i]]
ml <- attr(m[[i]], "match.length")
sym <- substring(line, starts + 2, starts + ml - 2)
if (verbose)
cat("sym: |", sym, "|\n")
repl <- map[sym]
idx1 <- is.na(repl)
if (sum(idx1) > 0) {
warning("Don't know how to replace '", paste(sym[idx1],
collapse = "', '"), "'.")
repl[idx1] <- paste("$(", sym[idx1], ")", sep = "")
}
norepl <- substring(line, c(1, starts + ml), c(starts -
1, nchar(line)))
res[[i]] <- paste(norepl, c(repl, ""), sep = "", collapse = "")
if (verbose)
cat("output: |", res[[i]], "|\n")
}
return(res)
}

Related

R copy text from function output with for loop to clipboard

I've written a little function that helps renaming columns by looping through each variable and pasting various punctuation around it so that text is sent to the console. This can then be copied into my script and rename variables as required. This is the function:
library(tidyverse)
tidy_rename <- function (df) {
df_name <- deparse(substitute(df))
names(df) <- tolower(names(df))
cat(paste(df_name, " <- ", paste(df_name, "%>%\n\t rename(")))
for (i in names(df)) {
cat(paste("\t\t", paste(paste("=", paste(paste('"', i), '"'))), ","), sep="\n")
}
writeLines(")"
)
}
If I use this on a dataset:
test_df <- data.frame("VarIable 1" = c(1), "sizrd" = c(1), "dat 1" = c(1),
"x-cord" = c(1), "y-crf" = c(1), "aGe" = c(1), check.names=F)
tidy_rename(test_df)
which gives the following which can be copied and pasted into script:
test_df <- test_df %>%
rename( = " variable 1 " ,
= " sizrd " ,
= " dat 1 " ,
= " x-cord " ,
= " y-crf " ,
= " age " ,
)
What I would like is to automatically copy this output to the clipboard within the function. I'm not sure how to use writeClipboard around the forloop. This doesn't work:
tidy_rename <- function (df) {
df_name <- deparse(substitute(df))
names(df) <- tolower(names(df))
writeClipboard(
cat(paste(df_name, " <- ", paste(df_name, "%>%\n\t rename(")))
for (i in names(df)) {
cat(paste("\t\t", paste(paste("=", paste(paste('"', i), '"'))), ","), sep="\n")
}
writeLines(")"
)
)
}
Any suggestions please?
Expanding on my comment to eliminate any confusion.
A method or suggestion is to store the string in a variable, which can then be output in the end. Note from the value of cat(...) is NULL (it doesnt return the string). This requires 2 variables, lets call them str and newstr. I'll let str store the entire string that you want to copy, and newstr store the current string that is output by cat(...).
tidy_rename <- function (df) {
df_name <- deparse(substitute(df))
names(df) <- tolower(names(df))
str <- paste(df_name, " <- ", paste(df_name, "%>%\n\t rename("))
cat(str)
for (i in names(df)) {
#Store variable at each iteration and expand str. Output newstr.
newstr <- paste("\t\t", paste(paste("=", paste(paste('"', i), '"'))), ",")
str <- paste(str, newstr, sep = "\n")
cat(newstr, sep="\n")
}
newstr <- ")"
str <- paste0(str, newstr)
cat(newstr)
writeClipboard(str)
}
Note how the output is stored in str at each iteration but newstr is output.
As a side note i suggest that OP checks out the collapse argument of paste (alternatively paste0). I don't have the full overview, but it seems like this could eliminate 2 - 3 calls to paste if the strings were collapsed within one of the function calls.

How to replace the string with special characters in R in a loop?

I am trying to replace the strings with special characters using gsub. But I am running into error invalid regular expression '\bc++\b', reason 'Invalid use of repetition operators'.
df = data.frame("word"=c('c++', '.XLS','Java-prog'))
for i in nrow(df){
df$new[i] <- gsub(paste0("\\b", df$word[i], "\\b"), "xx", df$new[i],ignore.case = T)
}
Actual code:
data = data.frame("word"=c('python', 'java'),
"description"=c('Java-script is a statically typed and Python py is a dynamically typed',
'java is a programming language'), stringsAsFactors = FALSE)
ll <- as.list(data$word)
data$new <- data$description
for(i in seq_len(nrow(data))) for(j in seq_along(ll)) {
data$new[i] <- gsub(paste0("\\b", ll[j], "\\b"), "url", data$new[i],ignore.case = T)
}
The expectation is to replace the values with xx.

R paste function repeats first argument for each word

Below is a code snippet written for writing the messages. But im not getting why the output prints the way below. Expected output is also given. I first thought the txt is a list type. But it is a character variable
writetext<-function(...){
arguments <- list(...)
if (length(arguments)>0){
txt<- paste(arguments)
if (length(txt)==0) return()
strtime <- format(Sys.time(),"%I:%M:%S%p")
txt <- paste(strtime,txt)
message(txt)
}
}
writetext("abc","efg")
01:05:13PM abc01:05:13PM efg
Expected :
01:05:13PM abcefg
You could use paste0(txt, collapse = "") :
writetext <- function(...) {
arguments <- list(...)
if (length(arguments) > 0) {
txt <- paste(arguments)
if (length(txt) == 0) return()
strtime <- format(Sys.time(), "%I:%M:%S%p")
txt <- paste(strtime, paste0(txt, collapse = ""))
message(txt)
}
}
writetext("abc", "efg")
# 07:13:45PM abcefg

How can make a for loop not past NA when the index runs out?

xlen <- 50 # Length
xGRU <- seq(1, 2723, by = xlen) # Start ID
xjob <- 36 # Numbe of Jobs per Joblist
# List of all run Commands
runcommands <- paste("TESTTHIS", xGRU, xlen , '-r d', '-m', sep=" ")
runcommands <- append(head(runcommands, -1),
paste("TESTTHIS", tail(xGRU,1), 11723%%xlen ,
'-r d', '-m', sep=" "))
for(i in seq(1, length(runcommands), by = xjob)){
jobfileName <- paste0('data_raw/joblist_', i, ".txt")
cat(paste(runcommands[i:(i+xjob-1)]), file=jobfileName, append=TRUE, sep = "\n")
}
But the last file that is created has NAs in it. How can I ensure that the for loop doesn't write out NA when the index runs out?
Use ?lapply and simply drop the NA objects from each vector prior to writing
lapply(seq_along(runcommands), function(i){
# create a new file inside of the temporary directory
# for help see ?sprintf
fl <- sprintf('data_raw/joblist_%s.txt', i)
# cleaned up your seq chunk a bit, and then the key is to remove
# the NA items prior to writing to file
job_list <- runcommands[seq(i, i + (xjob - 1))] %>% .[!is.na(.)]
stringi::stri_write_lines(job_list, sep = "\n", fname = fl)
})
You could prevent this from happening by being more rigorous with your use of indices in the cat function call. But as a quick workaround you can do this:
for(i in seq(1, length(runcommands), by = xjob)){
jobfileName <- paste0('~/SO_posts/joblist_', i, ".txt")
cat(paste(na.omit(runcommands[i:(i+xjob-1)])), file=jobfileName, append=TRUE, sep = "\n")
}

How to parse INI like configuration files with R?

Is there an R function for parsing INI like configuration files?
While searching I only found this discussion.
Here is an answer that was given to exact the same question on r-help in 2007 (thanks to #Spacedman for pointing this out):
Parse.INI <- function(INI.filename)
{
connection <- file(INI.filename)
Lines <- readLines(connection)
close(connection)
Lines <- chartr("[]", "==", Lines) # change section headers
connection <- textConnection(Lines)
d <- read.table(connection, as.is = TRUE, sep = "=", fill = TRUE)
close(connection)
L <- d$V1 == "" # location of section breaks
d <- subset(transform(d, V3 = V2[which(L)[cumsum(L)]])[1:3],
V1 != "")
ToParse <- paste("INI.list$", d$V3, "$", d$V1, " <- '",
d$V2, "'", sep="")
INI.list <- list()
eval(parse(text=ToParse))
return(INI.list)
}
Actually, I wrote a short and presumably buggy function (i.e. not covering all corner cases) which works for me now:
read.ini <- function(x) {
if(length(x)==1 && !any(grepl("\\n", x))) lines <- readLines(x) else lines <- x
lines <- strsplit(lines, "\n", fixed=TRUE)[[1]]
lines <- lines[!grepl("^;", lines) & nchar(lines) >= 2] # strip comments & blank lines
lines <- gsub("\\r$", "", lines)
idx <- which(grepl("^\\[.+\\]$", lines))
if(idx[[1]] != 1) stop("invalid INI file. Must start with a section.")
res <- list()
fun <- function(from, to) {
tups <- strsplit(lines[(from+1):(to-1)], "[ ]*=[ ]*")
for (i in 1:length(tups))
if(length(tups[[i]])>2) tups[[i]] <- c(tups[[i]][[1]], gsub("\\=", "=", paste(tail(tups[[i]],-1), collapse="=")))
tups <- unlist(tups)
keys <- strcap(tups[seq(from=1, by=2, length.out=length(tups)/2)])
vals <- tups[seq(from=2, by=2, length.out=length(tups)/2)]
sec <- strcap(substring(lines[[from]], 2, nchar(lines[[from]])-1))
res[[sec]] <<- setNames(vals, keys)
}
mapply(fun, idx, c(tail(idx, -1), length(lines)+1))
return(res)
}
where strcap is a helper function that capitalizes a string:
strcap <- function(s) paste(toupper(substr(s,1,1)), tolower(substring(s,2)), sep="")
There are also some C solutions for this, like inih or libini that might be useful. I did not try them out, though.

Resources