Làm thế nào hai chuỗi có thể được nối?


375

Làm thế nào tôi có thể nối (hợp nhất, kết hợp) hai giá trị? Ví dụ tôi có:

tmp = cbind("GAD", "AB")
tmp
#      [,1]  [,2]
# [1,] "GAD" "AB"

Mục tiêu của tôi là nối hai giá trị trong "tmp" thành một chuỗi:

tmp_new = "GAD,AB"

Chức năng nào có thể làm điều này cho tôi?


Hầu hết các câu trả lời ở đây bị phá vỡ nếu các chuỗi là vectơ, như ghi chú câu trả lời của @ RichardScriven.
smci

@smci những gì về câu trả lời nhỏ tôi đã đăng? Bất kỳ đề xuất để cải thiện nó?
joel.wilson

Câu trả lời:


505
paste()

là con đường để đi Như các áp phích trước đã chỉ ra, dán có thể làm hai việc:

nối các giá trị thành một "chuỗi", vd

> paste("Hello", "world", sep=" ")
[1] "Hello world"

trong đó đối số sepchỉ định (các) ký tự được sử dụng giữa các đối số để nối hoặc thu gọn các vectơ ký tự

> x <- c("Hello", "World")
> x
[1] "Hello" "World"
> paste(x, collapse="--")
[1] "Hello--World"

trong đó đối số collapsechỉ định (các) ký tự được sử dụng giữa các phần tử của vectơ sẽ được thu gọn.

Bạn thậm chí có thể kết hợp cả hai:

> paste(x, "and some more", sep="|-|", collapse="--")
[1] "Hello|-|and some more--World|-|and some more"

Hi vọng điêu nay co ich.


9
Trộn các chuỗi và vectơ hoặc vectơ có độ dài khác nhau là một chút quá linh hoạt paste()theo ý thích của tôi. Ví dụ, paste(c('a','b'),'blah', c(1,2,3))kết quả trong "a blah 1" "b blah 2" "a blah 3". Về cơ bản, nó tạo ra một vectơ của các chuỗi có cùng độ dài với vectơ dài nhất được truyền vào và lặp các vectơ / chuỗi khác có cùng độ dài. Rất nhiều phòng cho hành vi tình cờ ở đó.
ness101

1
Đúng - nhưng bạn có thể cung cấp một cách tiếp cận khác để giải quyết câu hỏi không?
Rainer

1
không - câu trả lời của bạn là chính xác (như hầu hết các câu trả lời khác nói điều tương tự). Tôi chỉ lưu ý rằng hành vi của dán là bất thường trong tính linh hoạt của nó.
ness101

2
@ naught101 Tôi sẽ không coi đó là bất thường theo tiêu chuẩn của R. Vector tái chế là một tài sản chung của các chức năng R. Hãy nhớ rằng 'blah' là một vectơ có độ dài 1. Thuộc tính tái chế giúp bạn dễ dàng thực hiện điều gì đó muốn paste0("blah", 1:3)nhận "blah1" "blah2" "blah3".
Dason

5
Có, tôi nên phàn nàn về R, không chỉ dán: P. Nó thực sự không nhất quán trên R - data.frame()không cho phép bạn làm điều đó nếu các vectơ không phải là bội số của nhau. matrix()phun ra cảnh báo, nhưng array()không. Loại phiền phức. Thực sự, tất cả họ nên thốt ra những cảnh báo trừ khi có một số tùy chọn được đặt ra ...
naught101

85

help.search() là một chức năng tiện dụng, vd

> help.search("concatenate")

sẽ dẫn bạn đến paste().


42

Đối với paste()câu trả lời đầu tiên , chúng ta có thể xem stringr::str_c()(và sau đó toString()bên dưới). Nó không tồn tại lâu như câu hỏi này, vì vậy tôi nghĩ thật hữu ích khi đề cập rằng nó cũng tồn tại.

Rất đơn giản để sử dụng, như bạn có thể thấy.

tmp <- cbind("GAD", "AB")
library(stringr)
str_c(tmp, collapse = ",")
# [1] "GAD,AB"

Từ mô tả tập tin tài liệu của nó, nó phù hợp với vấn đề này độc đáo.

Để hiểu cách str_c hoạt động, bạn cần tưởng tượng rằng bạn đang xây dựng một ma trận các chuỗi. Mỗi đối số đầu vào tạo thành một cột và được mở rộng theo chiều dài của đối số dài nhất, sử dụng các quy tắc tái cấu trúc thông thường. Chuỗi sep được chèn giữa mỗi cột. Nếu thu gọn là NULL, mỗi hàng được thu gọn thành một chuỗi. Nếu không phải NULL thì chuỗi đó được chèn vào cuối mỗi hàng và toàn bộ ma trận được thu gọn thành một chuỗi.

Đã thêm vào ngày 13 tháng 4 năm 2016 : Nó không hoàn toàn giống với đầu ra mong muốn của bạn (không gian thêm), nhưng cũng không ai đề cập đến nó. toString()về cơ bản là một phiên bản paste()với collapse = ", "mã hóa cứng, vì vậy bạn có thể làm

toString(tmp)
# [1] "GAD, AB"

3
Heh, đây là câu trả lời duy nhất giải quyết thực tế rằng tmp là một vectơ, và không chỉ là một loạt các giá trị - pastekhông làm vectơ. Tùy chọn khác là do.call(paste, as.list(tmp)).
ness101

35

Như những người khác đã chỉ ra, paste()là con đường để đi. Nhưng nó có thể gây khó chịu khi phải gõ paste(str1, str2, str3, sep='')mỗi lần bạn muốn phân tách không mặc định.

Bạn có thể rất dễ dàng tạo các hàm bao bọc giúp cuộc sống đơn giản hơn nhiều. Chẳng hạn, nếu bạn thấy mình nối các chuỗi không có dấu phân cách thực sự thường xuyên, bạn có thể làm:

p <- function(..., sep='') {
    paste(..., sep=sep, collapse=sep)
}

hoặc nếu bạn thường muốn nối các chuỗi từ một vectơ (như implode()từ PHP):

implode <- function(..., sep='') {
     paste(..., collapse=sep)
}

Cho phép bạn làm điều này:

p('a', 'b', 'c')
#[1] "abc"
vec <- c('a', 'b', 'c')
implode(vec)
#[1] "abc"
implode(vec, sep=', ')
#[1] "a, b, c"

Ngoài ra, có tích hợp sẵn paste0, hoạt động tương tự như của tôi implode, nhưng không cho phép phân tách tùy chỉnh. Nó hiệu quả hơn một chút paste().



28

Ngoài ra, nếu mục tiêu của bạn là xuất trực tiếp ra tệp hoặc thiết bị xuất chuẩn, bạn có thể sử dụng cat:

cat(s1, s2, sep=", ")

4
Vì vậy, những gì điểm đăng một pastecâu trả lời 4 năm sau khi đã có khoảng một tá pastecâu trả lời?
David Arenburg

4
Tại thời điểm đó tôi thấy hữu ích để tóm tắt nhiều câu trả lời cho chính mình. Mục tiêu không phải là để thu thập phiếu bầu mà là giúp người khác lọc qua nhiều giải pháp được đưa ra. Thường thì đó là những gì tôi đang tìm kiếm.
Megatron

22

Cách khác:

sprintf("%s you can add other static strings here %s",string1,string2)

Nó đôi khi hữu ích hơn paste()chức năng. %sbiểu thị nơi bao gồm các chuỗi chủ quan.

Lưu ý rằng điều này sẽ có ích khi bạn cố gắng xây dựng một đường dẫn:

sprintf("/%s", paste("this", "is", "a", "path", sep="/"))

đầu ra

/this/is/a/path

đối với các lập trình viên C giao dịch với R, sprintf rất quen thuộc và hữu ích cho việc "nối hai chuỗi"
subsci

Imho tốt hơn nhiều. pastekhông đủ linh hoạt nếu bạn muốn nối một cái gì đó vào một chuỗi.
hiển thị

20

Bạn có thể tạo toán tử của riêng bạn:

'%&%' <- function(x, y)paste0(x,y)
"new" %&% "operator"
[1] newoperator`

Bạn cũng có thể xác định lại toán tử 'và' ( &):

'&' <- function(x, y)paste0(x,y)
"dirty" & "trick"
"dirtytrick"

làm rối với cú pháp cơ sở là xấu, nhưng sử dụng paste()/paste0()nếu bạn chỉ làm việc với mã của riêng mình, bạn có thể (hầu như luôn luôn) thay thế & andtoán tử logic bằng *và nhân các giá trị logic thay vì sử dụng logic 'và &'


@Richard Scriven mayby ​​Tôi không hiểu, nhưng có vẻ đơn giản, so sánh: paste0(as.matrix(iris[1:4]) , as.matrix(iris[1:4]))as.matrix(iris[1:4]) %&% as.matrix(iris[1:4])
Qbik

rất tốt! & là tiêu chuẩn để ghép nối trong nhiều ngôn ngữ, tôi thực sự nghĩ rằng R nên có nó theo mặc định. khuyến khích theo cách này
Serhii

14

Đưa ra ma trận, tmp, mà bạn đã tạo:

paste(tmp[1,], collapse = ",")

Tôi giả sử có một số lý do tại sao bạn tạo ma trận bằng cbind, trái ngược với đơn giản:

tmp <- "GAD,AB"

3

Hãy xem xét trường hợp các chuỗi là các cột và kết quả sẽ là một cột mới:

df <- data.frame(a = letters[1:5], b = LETTERS[1:5], c = 1:5)

df$new_col <- do.call(paste, c(df[c("a", "b")], sep = ", ")) 
df
#  a b c new_col
#1 a A 1    a, A
#2 b B 2    b, B
#3 c C 3    c, C
#4 d D 4    d, D
#5 e E 5    e, E

Tùy chọn, bỏ qua tập hợp con [c("a", "b")]nếu tất cả các cột cần được dán.

# you can also try str_c from stringr package as mentioned by other users too!
do.call(str_c, c(df[c("a", "b")], sep = ", ")) 

Ok nhưng stringi, stringrthư viện nhanh hơn.
smci

2

Một câu trả lời không dán khác:

x <- capture.output(cat(data, sep = ","))
x
[1] "GAD,AB"

Ở đâu

 data <- c("GAD", "AB")

2

gluelà một chức năng mới, lớp dữ liệu và gói đã được phát triển như một phần của tidyverse, với rất nhiều chức năng mở rộng. Nó kết hợp các tính năng từ dán, chạy nước rút và các câu trả lời khác trước đó.

tmp <- tibble::tibble(firststring = "GAD", secondstring = "AB")
(tmp_new <- glue::glue_data(tmp, "{firststring},{secondstring}"))
#> GAD,AB

Được tạo vào ngày 2019-03-06 bởi gói reprex (v0.2.1)

Vâng, nó quá mức cho ví dụ đơn giản trong câu hỏi này, nhưng mạnh mẽ cho nhiều tình huống. (xem https://glue.tidyverse.org/ )

Ví dụ nhanh so pastevới withbên dưới. Các gluemã đã được một chút dễ dàng hơn để gõ và trông hơi dễ đọc hơn.

tmp <- tibble::tibble(firststring = c("GAD", "GAD2", "GAD3"), secondstring = c("AB1", "AB2", "AB3"))
(tmp_new <- glue::glue_data(tmp, "{firststring} and {secondstring} went to the park for a walk. {firststring} forgot his keys."))
#> GAD and AB1 went to the park for a walk. GAD forgot his keys.
#> GAD2 and AB2 went to the park for a walk. GAD2 forgot his keys.
#> GAD3 and AB3 went to the park for a walk. GAD3 forgot his keys.
(with(tmp, paste(firststring, "and", secondstring, "went to the park for a walk.", firststring, "forgot his keys.")))
#> [1] "GAD and AB1 went to the park for a walk. GAD forgot his keys."  
#> [2] "GAD2 and AB2 went to the park for a walk. GAD2 forgot his keys."
#> [3] "GAD3 and AB3 went to the park for a walk. GAD3 forgot his keys."

Được tạo vào ngày 2019-03-06 bởi gói reprex (v0.2.1)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.