Paste/Collapse in R - r

I'm confused by paste, and thought it was just simple concatenating.
whales <- c("C","D","C","D","D")
quails <- c("D","D","D","D","D")
results <-paste(whales, quails, collapse = '')
Why would this return "C DD DC DD DD D" instead of CD DD CD DD DD?
Moreover, why would
results <-paste(whales[1], quails[1], collapse = '')
return
"C D" ?
with a space?
Thanks,
D
EDIT
OK, I see that
results <-paste(whales, quails, collapse = NULL, sep='')
will get me what I want, but an explanation of why the previous code didn't work? And also thank you to the answerers.

For those who like visuals, here is my take at explaining how paste works in R:
sep creates element-wise sandwich stuffed with the value in the sep argument:
collapse creates ONE big sandwich with the value of collapse argument added between the sandwiches produced by using the sep argument:

For the first question, try the following (which might be more illustrative than choosing to repeat 2 characters).
### Note that R paste's together corresponding elements together...
paste(c("A", "S", "D", "F"),
c("W", "X", "Y", "Z"))
[1] "A W" "S X" "D Y" "F Z"
### Note that with collapse, R converts the above
# result into a length 1 character vector.
paste(c("A", "S", "D", "F"),
c("W", "X", "Y", "Z"), collapse = '')
[1] "A WS XD YF Z"
What you really want to do (to get the "desired" result) is the following:
### "Desired" result:
paste(whales, quails, sep = '', collapse = ' ')
[1] "CD DD CD DD DD"
Note that we are specifying the sep and collapse arguments to different values, which relates to your second question. sep allows each terms to be separated by a character string, whereas collapse allows the entire result to be separated by a character string.
Try
paste(whales, quails, collapse = '', sep = '')
[1] "CDDDCDDDDD"
Alternatively, use a shortcut paste0, which defaults to paste with sep = ''
paste0(whales, quails, collapse = '')

Related

In R, print vector in single quotes and comma separated

Problem Statement: I'm creating a dynamic application in which user select inputs and they are passed into URL to filter data. User can select single or multiple values. I'm using knitr::combine_words(Selected_Input, before = ",", and = "", sep = ",") to get them in single quotes and comma separated. But facing issue when user selects single value (as described below):
#User selecting multiple values
Selected_Input <- c("Apple","Banana","Cherry")
knitr::combine_words(Selected_Input, before = ",", and = "", sep = ",")
Result: 'Apple','Banana','Cherry' which works for my code.
But when user selects single value
#User selecting single value
Selected_Input <- c("Apple")
knitr::combine_words(Selected_Input, before = ",", and = "", sep = ",")
Result: ,Apple, which doesn't work. As it should be single quoted.
I'm using this knitr::combine_words inside paste0 to create a dynamic URL. So I'm looking for a way which works inside paste0.
If I'm using cat() function inside paste0 then the output doesn't work in my code. The url doesn't fall in place.
vector <- c("apple", "banana", "cherry")
out <- paste(sQuote(vector, FALSE), collapse=", ")
cat(out, "\n")
#> 'apple', 'banana', 'cherry'
cat(toString(sQuote(vector, FALSE)))
paste0("url",cat(toString(sQuote(vector, FALSE))),"url")
Result: 'apple', 'banana', 'cherry'[1] "urlurl"
What about:
fruits <- c("apple", "banana", "cherry")
all_fruit_in_one <- paste0(paste0("'", fruits, "'"), collapse = ", ")
cat(all_fruit_in_one)
Output:
'apple', 'banana', 'cherry'
Another option using sQuote:
Single or double quote text by combining with appropriate single or
double left and right quotation marks.
vector <- c("apple", "banana", "cherry")
out <- paste(sQuote(vector, FALSE), collapse=", ")
cat(out, "\n")
#> 'apple', 'banana', 'cherry'
Created on 2022-07-08 by the reprex package (v2.0.1)
I think it was just because of a typo in your code, i.e., it should be before = "'" instead of before = ",".
> Selected_Input <- c("Apple","Banana","Cherry")
> knitr::combine_words(Selected_Input, before = "'", and = "", sep = ",")
'Apple','Banana','Cherry'
> Selected_Input <- c("Apple")
> knitr::combine_words(Selected_Input, before = "'", and = "", sep = ",")
'Apple'
Use sprintf to insert the quotes and then use toString (assuming that comma with a space is acceptable as the separator). Optionally cat or print the result depending on exactly what you want; however, simply entering it into the console will print it.
toString(sprintf("'%s'", fruits))
## [1] "'apple', 'banana', 'cherry'"
toString(sprintf("'%s'", fruits[1]))
## [1] "'apple'"
This can also be expressed in terms of pipes:
fruits |> sprintf(fmt = "'%s'") |> toString()
## [1] "'apple', 'banana', 'cherry'"
Note
The input in reproducible form is assumed to be:
fruits <- c("apple", "banana", "cherry")

How can I get the output of this function to print onto different lines in R?

So, I am writing a function that, among many other things, is supposed to keep only the first sentence from each paragraph of a text and preserve the paragraph structure (i.e. each sentence is in its own line). Here is the code that I have so far:
text_shortener <- function(input_text) {
lapply(input_text, function(x)str_split(x, "\\.", simplify = T)[1])
first.sentences <- unlist(lapply(input_text, function(x)str_split(x, "\\.", simplify = T)[1]))
no.spaces <- gsub(pattern = "(?<=[\\s])\\s*|^\\s+|\\s+$", replacement = "", x = first.sentences, perl = TRUE)
stopwords <- c("the", "really", "truly", "very", "The", "Really", "Truly", "Very")
x <- unlist(strsplit(no.spaces, " "))
no.stopwords <- paste(x[!x %in% stopwords], collapse = " ")
final.text <- gsub(pattern = "(?<=\\w{5})\\w+", replacement = ".", x = no.stopwords, perl=TRUE)
return(final.text)
}
All of the functions are working as they should, but the one part I can't figure out is how to get the output to print onto separate lines. When I run the function with a vector of text (I was using some text from Moby Dick as a test), this is what I get:
> text_shortener(Moby_Dick)
[1] "Call me Ishma. It is a way I have of drivi. off splee., and regul. circu. This is my subst. for pisto. and ball"
What I want is for the output of this function to look like this:
[1] "Call me Ishma."
[2] "It is a way I have of drivi. off splee., and regul. circu."
[3] "This is my subst. for pisto. and ball"
I am relatively new to R and this giving me a real headache, so any help would be much appreciated! Thank you!
Looking at your output, it seems like splitting on a period followed by a capital letter if what you need.
You could accomplish that with strsplit() and split the string up like so:
strsplit("Call me Ishma. It is drivi. off splee., and regul. circu. This is my subst. for pisto.","\\. (?=[A-Z])", perl=T)
That finds instances where a period is followed by a space and a capital letter and splits the character up there.
Edit: You could add it to the end of your function like so:
text_shortener <- function(input_text) {
lapply(input_text, function(x)str_split(x, "\\.", simplify = T)[1])
first.sentences <- unlist(lapply(input_text, function(x)str_split(x, "\\.", simplify = T)[1]))
no.spaces <- gsub(pattern = "(?<=[\\s])\\s*|^\\s+|\\s+$", replacement = "", x = first.sentences, perl = TRUE)
stopwords <- c("the", "really", "truly", "very", "The", "Really", "Truly", "Very")
x <- unlist(strsplit(no.spaces, " "))
no.stopwords <- paste(x[!x %in% stopwords], collapse = " ")
trim.text <- gsub(pattern = "(?<=\\w{5})\\w+", replacement = ".", x = no.stopwords, perl=TRUE)
final.text <- strsplit(trim.text, "\\. (?=[A-Z])", perl=T)
return(final.text)
}

Simple way to print a vector and string in one return value in R [duplicate]

I'm confused by paste, and thought it was just simple concatenating.
whales <- c("C","D","C","D","D")
quails <- c("D","D","D","D","D")
results <-paste(whales, quails, collapse = '')
Why would this return "C DD DC DD DD D" instead of CD DD CD DD DD?
Moreover, why would
results <-paste(whales[1], quails[1], collapse = '')
return
"C D" ?
with a space?
Thanks,
D
EDIT
OK, I see that
results <-paste(whales, quails, collapse = NULL, sep='')
will get me what I want, but an explanation of why the previous code didn't work? And also thank you to the answerers.
For those who like visuals, here is my take at explaining how paste works in R:
sep creates element-wise sandwich stuffed with the value in the sep argument:
collapse creates ONE big sandwich with the value of collapse argument added between the sandwiches produced by using the sep argument:
For the first question, try the following (which might be more illustrative than choosing to repeat 2 characters).
### Note that R paste's together corresponding elements together...
paste(c("A", "S", "D", "F"),
c("W", "X", "Y", "Z"))
[1] "A W" "S X" "D Y" "F Z"
### Note that with collapse, R converts the above
# result into a length 1 character vector.
paste(c("A", "S", "D", "F"),
c("W", "X", "Y", "Z"), collapse = '')
[1] "A WS XD YF Z"
What you really want to do (to get the "desired" result) is the following:
### "Desired" result:
paste(whales, quails, sep = '', collapse = ' ')
[1] "CD DD CD DD DD"
Note that we are specifying the sep and collapse arguments to different values, which relates to your second question. sep allows each terms to be separated by a character string, whereas collapse allows the entire result to be separated by a character string.
Try
paste(whales, quails, collapse = '', sep = '')
[1] "CDDDCDDDDD"
Alternatively, use a shortcut paste0, which defaults to paste with sep = ''
paste0(whales, quails, collapse = '')

Function to generate a random password

I want to generate a random password for employees with the function below. This is my first attempt with functions in R. So I need a bit help.
genPsw <- function(num, len=8) {
# Vorgaben für die Passwortkonventionen festlegen
myArr <- c("", 2, 3, 4, 5, 6, 7, 8, 9, "A", "B",
"C", "D", "E", "F", "G", "H", "J", "K", "L", "M",
"N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"!", "§", "$", "%", "&", "(", ")", "*")
# replicate is a wrapper for the common use of sapply for repeated evaluation of an expression
# (which will usually involve random number generation).
replicate(num, paste(sample(myArr, size=len, replace=T), collapse=""))
# nrow of dataframe mitarbeiter
dim_mitarbeiter <- nrow(mitarbeiter)
for(i in 1:dim_mitarbeiter) {
# Random Number Generation with i
set.seed(i)
# Generate Passwort for new variable password
mitarbeiter$passwort <- genPsw(i)
}
}
With the answer form Floo0 I've changed the function to somthing like that, but it doesn't work:
genPsw <- function(num, len=8) {
# Vorgaben für die Passwortkonventionen festlegen
sam<-list()
sam[[1]]<-1:9
sam[[2]]<-letters
sam[[3]]<-LETTERS
sam[[4]]<-c("!", "§", "$", "%", "&", "(", ")", "*")
# nrow of dataframe mitarbeiter
dim_mitarbeiter <- nrow(mitarbeiter)
for(i in 1:dim_mitarbeiter) {
# Random Number Generation with i
tmp<-mapply(sample,sam,c(2,2,2,2))
# Generate Passwort for new variable password
mitarbeiter$passwort <- paste(sample(tmp),collapse="")
}
}
What about
samp<-c(2:9,letters,LETTERS,"!", "§", "$", "%", "&", "(", ")", "*")
paste(sample(samp,8),collapse="")
result is something like this
"HKF§VvnD"
Caution:
This approch does not enforce having capitals, numbers, and non alpha numeric symbols
EDIT:
If you want to enforce a certain number of capitals, numbers, and non alpha numeric symbols you could go with this:
sam<-list()
sam[[1]]<-1:9
sam[[2]]<-letters
sam[[3]]<-LETTERS
sam[[4]]<-c("!", "§", "$", "%", "&", "(", ")", "*")
tmp<-mapply(sample,sam,c(2,2,2,2))
paste(sample(tmp),collapse="")
Where c(2,2,2,2) specifies the number of numbers, letters, capital letters and symbild (in this order). Result:
[1] "j$bP%5R3"
EDIT2:
To produce an new column in you table mitarbeiter just use
passwort<-replicate(nrow(mitarbeiter),paste(mapply(sample,sam,c(2,2,2,2)),collapse=""))
mitarbeiter$passwort<-passwort
There is function which generates random strings in stringi package:
require(stringi)
stri_rand_strings(n=2, length=8, pattern="[A-Za-z0-9]")
## [1] "90i6RdzU" "UAkSVCEa"
This might work, one might want to alter ASCII to avoid unwanted symbols:
generatePwd <- function(plength=8, ASCII=c(33:126)) paste(sapply(sample(ASCII, plength), function(x) rawToChar(as.raw(x))), collapse="")
The below script creates a password of specified length from a combination of upper and lowercase letters, digits and 32 symbols (punctuation, etc.).
# Store symbols as a vector in variable punc
R> library(magrittr) # Load this package to use the %>% (pipe) operator
R> punc_chr <- "!#$%&’()*+,-./:;<=>?#[]^_`{|}~" %>%
str_split("", simplify = TRUE) %>%
as.vector() -> punc
# Randomly generate specified number of characters from 94 characters
R> sample(c(LETTERS, letters, 0:9, punc), 8) %>%
paste(collapse = "") -> pw
R> pw # Return password
[1] "fAXVpyOs"
I like the brevity of L.R.'s solution, although I don't follow what it does 100%.
My solution allows to specify the length of the password but also ensures that at least one lower case, one upper case, one numeric, and one special character is included, and allows reproducibility. (ht to moazzem for spelling out all the special characters.)
gen_pass <- function(len=8,seeder=NULL){
set.seed(seeder) # to allow replicability of passw generation
# get all combinations of 4 nums summing to length len
all_combs <- expand.grid(1:(len-3),1:(len-3),1:(len-3),1:(len-3))
sum_combs <- all_combs[apply(all_combs, 1, function(x) sum(x)==len),]
# special character vector
punc <- unlist(strsplit("!#$%&’()*+,-./:;<=>?#[]^_`{|}~",""))
# list of all characters to sample from
chars <- list(punc,LETTERS,0:9,letters)
# retrieve the number of characters from each list element
# specified in the sampled row of sum_combs
pass_chars_l<- mapply(sample, chars,
sum_combs[sample(1:nrow(sum_combs),1),],
replace = TRUE)
# unlist sets of password characters
pass_chars <- unlist(pass_chars_l)
# jumble characters and combine into password
passw <- str_c(sample(pass_chars),collapse = "")
return(passw)
}
I am still wondering how the (1:(len-3),1:(len-3),1:(len-3),1:(len-3)) in expand.grid(1:(len-3),1:(len-3),1:(len-3),1:(len-3)) can be expressed more elegantly?
I have just tried the function proposed by Fmerhout. It seems like an excellent solution. thanks a lot. But because of the last line of code:
passw <- str_c (sample (pass_chars), collapse = "")
the function does not work.
I tried :
passw <- str (sample (pass_chars), collapse = "")
... and now it works:
example with a seed:
>gen_pass(4,2)
gives: chr [1:4] "y" "[" "O" "1"
In order to obtain a directly usable password, I changed the end of the code this way:
zz <- sample(pass_chars)
passw <- paste(zz, sep = "", collapse = "")
return(passw)
}
So, now we get for example:
> gen_pass(35, 2)
[1] "0OD}1O}8DKMqTL[JEFZBwKMJWGD’VZ=VRnD"
It's interesting; because we only have to remember the parameters passed to the function. here, in this case: 35 2.
Thank you Mr Fmerhout.
To conclude : with this little script we have a good way to create very strong and very safe passwords with good entropy without having to use a dictionary and without having to record in any place our passwords .

Column names of a data.frame separated with comma

I want to get column names of a data.frame separated with comma (,). I remembered I got this result in past but now forgot the command.
df<- data.frame(x=1:10, y=11:20)
names(df)
Output
"x" "y"
Desired Output
c("x", "y")
The easiest way to get exactly what it sounds like you're asking for (without knowing exactly how you plan to use this information) is to use dput:
dput(names(df))
# c("x", "y")
By extension, without fussing with paste:
x <- capture.output(dput(names(df)))
x
# [1] "c(\"x\", \"y\")"
cat(x)
# c("x", "y")
Although #Jilber deleted his answer, you can use shQuote to go from what he had started with to the output of "x" above:
paste("c(", paste(shQuote(names(df)), collapse = ", "), ")", sep = "")
# [1] "c(\"x\", \"y\")"

Resources