paste()
paste(..., sep = " ", collapse = NULL, recycle0 = FALSE) The paste() function concatenates its arguments after converting them to character strings. Unlike paste0(), it inserts a separator between elements.
Syntax
paste(..., sep = " ", collapse = NULL, recycle0 = FALSE)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
... | objects | , | Objects to concatenate, coerced to character |
sep | character | " " | Separator string inserted between arguments |
collapse | character | NULL | Optional string to collapse result into single string |
recycle0 | logical | FALSE | If TRUE, zero-length arguments return NA instead of empty string |
Examples
Basic concatenation
The default behaviour of paste() inserts a single space between each argument, which matches the most common use case: joining words into a readable phrase. Changing the sep parameter lets you switch to any delimiter — hyphens for identifiers, underscores for variable names, or an empty string for compact concatenation. The function coerces every argument through as.character(), so you can pass numbers, logical values, and factors alongside strings without explicit conversion, which makes paste() the go-to choice for assembling labels and messages in exploratory scripts.
paste("Hello", "World")
# [1] "Hello World"
# Using a custom separator
paste("Hello", "World", sep = "-")
# [1] "Hello-World"
Working with vectors
When you pass vectors as arguments, paste() aligns them position by position and recycles shorter vectors to match the length of the longest one. This element-wise behaviour is what makes paste() useful for building sequences of labels — you provide a prefix vector of length 1 and a numeric sequence, and R recycles the prefix across every index without you writing a loop. Understanding the recycling rules helps avoid surprises: if the longer vector’s length is not a multiple of the shorter vector’s length, R emits a warning but still produces a result, which can lead to subtle mismatches if you are not paying attention.
# Each element is concatenated
paste(c("a", "b"), c("1", "2"))
# [1] "a 1" "b 2"
# Separator is recycled
paste(c("x", "y"), 1:3, sep = "_")
# [1] "x_1" "y_2" "x_3"
Collapsing into a single string
Setting collapse to a non-NULL string changes paste() from a vector-producing function into one that returns a single character scalar. The collapse argument is applied after all element-wise concatenation completes — each pair of elements is joined with sep first, and then the resulting vector is flattened into one string with collapse inserted between each element. This two-stage process means you can build structured strings like "key1=val1; key2=val2" in a single call by passing key and value vectors and setting sep="=" and collapse="; " simultaneously.
words <- c("apple", "banana", "cherry")
# Collapse into one string
paste(words, collapse = ", ")
# [1] "apple, banana, cherry"
# Combine vectors then collapse
paste(c("A", "B"), c("1", "2"), collapse = "-")
# [1] "A 1-B 2"
Difference from paste0()
The only difference between paste() and paste0() is the default separator: paste() uses a space and paste0() uses an empty string. Both accept the same collapse and recycle0 arguments and behave identically once you set sep explicitly. The paste0() function exists purely as a convenience — writing paste0("x", 1:5) is shorter than paste("x", 1:5, sep="") — and it has become the conventional choice in the R community whenever no separator is needed, such as when assembling file names from a stem and an index or building compact identifiers from prefixes and numeric codes.
# paste0 is equivalent to sep = ""
paste0("Hello", "World")
# [1] "HelloWorld"
paste("Hello", "World", sep = "")
# [1] "HelloWorld"
Common patterns
Building file paths
While paste() can assemble file paths by joining folder and file names with "/" as the separator, the dedicated file.path() function is preferred for this task because it handles platform-specific path separators and normalises multiple slashes automatically. On Windows, file.path() uses backslashes; on Linux and macOS, it uses forward slashes. Using paste() for paths works on Unix-like systems but creates broken paths on Windows, so file.path() should be the default choice in any code that might run across operating systems, including packages submitted to CRAN.
folder <- "data"
file <- "file.csv"
paste(folder, file, sep = "/")
# [1] "data/file.csv"
# Using file.path() is preferred for paths
file.path(folder, file)
# [1] "data/file.csv"
Creating labels
Generating sequences of formatted labels is one of the most common applications of paste() in data analysis scripts. By passing a fixed string prefix and a numeric sequence, you produce labels like "Item_1" through "Item_5" in a single vectorised call. This approach scales to any length without rewriting code and works well inside dplyr::mutate() for adding a label column, inside names() for setting column names programmatically, or inside plot functions for constructing axis tick labels from computed break points.
paste("Item", 1:5, sep = "_")
# [1] "Item_1" "Item_2" "Item_3" "Item_4" "Item_5"
Combining with apply
When you need to concatenate values across columns within each row of a data frame, apply() with MARGIN = 1 hands each row as a vector to paste(), which collapses it into a single string. This row-wise string assembly is useful for creating composite keys from multiple columns — for instance, combining first and last names into a full-name column or merging date components into an ISO-formatted string. The collapse argument controls how the row values are joined; using ":" as shown below produces compact row summaries, while ", " would produce more readable output for display purposes.
df <- data.frame(x = 1:3, y = c("a", "b", "c"))
apply(df, 1, paste, collapse = ":")
# [1] "1:a" "2:b" "3:c"
paste() vs paste0() vs sprintf()
paste() concatenates strings with a separator between each element. The default separator is a space (sep = " "). paste0() is shorthand for paste(..., sep = "") — no separator. Both also have a collapse argument for collapsing a vector into a single string.
Use paste() or paste0() for simple string building where the structure is straightforward. Use sprintf() when you need to format numbers within strings (controlling decimal places, padding, or scientific notation), or when building SQL or HTML where the template structure is complex enough that positional %s placeholders are clearer than concatenation.
paste() is vectorized and recycles shorter vectors: paste("item", 1:3) produces c("item 1", "item 2", "item 3"). This recycling makes it efficient for creating labeled sequences without explicit loops.
When collapsing a vector to a single string, paste(x, collapse = ", ") is more readable than Reduce(function(a, b) paste(a, b, sep = ", "), x).
paste() and paste0() in practice
paste() vectorizes over all of its arguments simultaneously. When all arguments are vectors of the same length, it concatenates element-wise: paste(c("a","b"), c("1","2")) gives c("a 1", "b 2"). When arguments have different lengths, they are recycled. paste("item", 1:5) gives c("item 1", "item 2", ...). This vectorization is the core reason paste() is preferred over a loop for string construction.
The collapse argument concatenates the entire result vector into a single string: paste(c("a","b","c"), collapse=", ") gives "a, b, c". Used together with element-wise concatenation: paste(names, values, sep="=", collapse="; ") builds a key-value string from two vectors in one call.
For performance-critical code with very large inputs, paste() is slower than stri_paste() from the stringi package because it converts its arguments through as.character() on each call. For simple string building without type conversion concerns, the difference is negligible at the scales typical in data analysis.
paste0() is paste() with sep="", and is the conventional choice when no separator is needed. Both functions return NA when any input element is NA — if you need to treat NA as the string "NA", first replace with tidyr::replace_na() or coalesce(). Using sprintf() with %s format codes is an alternative when the template structure is complex or when you need to format numeric values at the same time.
Building SQL-style WHERE clauses with paste()
# Programmatically construct a SQL WHERE clause from column-value pairs
columns <- c("status", "region", "score")
values <- c("'active'", "'east'", "> 50")
# Build individual conditions
conditions <- paste(columns, values, sep = " = ")
# Collapse with AND
where_clause <- paste(conditions, collapse = " AND ")
where_clause
# [1] "status = 'active' AND region = 'east' AND score = > 50"
# Full query assembly
query <- paste("SELECT * FROM users WHERE", where_clause)
query
# [1] "SELECT * FROM users WHERE status = 'active' AND region = 'east' AND score = > 50"
When constructing parameterised queries or dynamic reports, paste() with both sep and collapse handles the full two-stage assembly in one pipeline. Each pair from columns and values is joined with " = " via the element-wise sep argument, producing a vector of conditions. The collapse argument then joins all conditions into a single string with " AND " between them. The same pattern adapts to URL query strings by swapping sep = "=" and collapse = "&", or to CSV headers by setting collapse = ",".