Jak można połączyć dwa łańcuchy?


375

Jak mogę połączyć (połączyć, połączyć) dwie wartości? Na przykład mam:

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

Moim celem jest połączenie dwóch wartości w „tmp” w jeden ciąg:

tmp_new = "GAD,AB"

Która funkcja może to dla mnie zrobić?


Większość odpowiedzi tutaj łamie się, jeśli ciągi są wektorami, jak zauważa odpowiedź @ RichardScriven.
smci

@smci co z małą odpowiedzią, którą opublikowałem? jakieś sugestie, aby to poprawić?
joel.wilson

Odpowiedzi:


505
paste()

jest droga. Jak zauważyli poprzedni plakaty, wklej może zrobić dwie rzeczy:

łączyć wartości w jeden „ciąg”, np

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

gdzie argument sepokreśla znak (znaki), które mają być użyte między argumentami w celu połączenia lub zwinięcia wektorów znaków

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

gdzie argument collapseokreśla znak (znaki), które mają być użyte między elementami wektora, który ma zostać zwinięty.

Możesz nawet połączyć oba:

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

Mam nadzieję że to pomoże.


9
Mieszanie łańcuchów i wektorów lub wektorów o różnych długościach jest dla mnie trochę zbyt elastyczne paste(). Na przykład paste(c('a','b'),'blah', c(1,2,3))wyniki w "a blah 1" "b blah 2" "a blah 3". Zasadniczo tworzy wektor łańcuchów o tej samej długości co najdłuższy wektor, który jest przekazywany i zapętla inne wektory / łańcuchy na tę samą długość. Dużo miejsca na przypadkowe zachowanie.
naught101

1
To prawda - ale czy możesz podać alternatywne podejście, które odpowie na pytanie?
Rainer,

1
nie - Twoja odpowiedź jest poprawna (podobnie jak większość innych odpowiedzi, które mówią to samo). Właśnie zauważyłem, że zachowanie pasty jest niezwykłe pod względem elastyczności.
naught101

2
@ naught101 Nie uważam, że jest to niezwykłe według standardów R. Recykling wektorów jest wspólną własnością funkcji R. Należy pamiętać, że „bla” jest wektorem długości 1. Właściwość recyklingu ułatwia zrobienie czegoś takiego jak paste0("blah", 1:3)zdobycie "blah1" "blah2" "blah3".
Dason,

5
Tak, powinienem narzekać na R, a nie tylko na wklejanie: P. W rzeczywistości jest to niespójne w całym R - data.frame()nie pozwala ci tego zrobić, jeśli wektory nie są wielokrotnością siebie. matrix()wyrzuca ostrzeżenia, ale array()nie robi tego. Trochę irytujące. Naprawdę, wszyscy powinni wypluć ostrzeżenia, chyba że ustawiono jakąś opcję ...
naught101

85

help.search() jest przydatną funkcją, np

> help.search("concatenate")

doprowadzi cię do paste().


42

W przypadku pierwszego braku paste()odpowiedzi możemy spojrzeć na stringr::str_c()(a następnietoString() poniżej). To pytanie nie istniało tak długo, więc myślę, że warto wspomnieć, że istnieje.

Bardzo prosty w użyciu, jak widać.

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

Z opisu pliku dokumentacji ładnie pasuje do tego problemu.

Aby zrozumieć, jak działa str_c, musisz sobie wyobrazić, że budujesz macierz ciągów. Każdy argument wejściowy tworzy kolumnę i jest rozszerzany do długości najdłuższego argumentu, przy użyciu zwykłych reguł recyklingu. Ciąg sep jest wstawiany między każdą kolumnę. Jeśli zwinięcie ma wartość NULL, każdy wiersz jest zwinięty w pojedynczy ciąg. Jeśli ciąg inny niż NULL jest wstawiany na końcu każdego wiersza, a cała macierz jest zwinięta do pojedynczego ciągu.

Dodano 13.04.2016 : To nie jest dokładnie to samo, co pożądane wyjście (dodatkowe miejsce), ale nikt też o tym nie wspomniał. toString()jest w zasadzie wersją paste()z collapse = ", "zakodowanym na stałe, więc możesz to zrobić

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

3
Heh, to jedyna odpowiedź, która dotyczy faktu, że tmp jest wektorem, a nie tylko zbiorem wartości - pastenie robi wektorów. Inną opcją jest do.call(paste, as.list(tmp)).
naught101

35

Jak zauważyli inni, paste()jest to najlepsza droga. Ale denerwujące może być paste(str1, str2, str3, sep='')pisanie za każdym razem, gdy chcesz użyć domyślnego separatora.

Możesz bardzo łatwo tworzyć funkcje opakowania, które znacznie upraszczają życie. Na przykład, jeśli często łączysz łańcuchy bez separatora, możesz:

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

lub jeśli często chcesz łączyć ciągi z wektora (np. implode()z PHP):

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

Pozwala to zrobić:

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

Jest też wbudowana funkcja paste0, która robi to samo co moja implode, ale nie zezwala na niestandardowe separatory. Jest nieco bardziej wydajny niż paste().



28

Alternatywnie, jeśli Twoim celem jest wyjście bezpośrednio do pliku lub standardowego wyjścia, możesz użyć cat:

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

4
Po co więc pisać pasteodpowiedź 4 lata później, kiedy już jest kilkanaście pasteodpowiedzi?
David Arenburg,

4
Wówczas uznałem za pomocne podsumowanie wielu odpowiedzi dla siebie. Celem nie było zbieranie głosów, ale pomoc innym w filtrowaniu wielu oferowanych rozwiązań. Często tego szukam.
Megatron

22

Inny sposób:

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

Czasami jest przydatny niż paste()funkcja. %soznacza miejsce, w którym zostaną uwzględnione ciągi subiektywne.

Pamiętaj, że przyda się to podczas próby zbudowania ścieżki:

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

wynik

/this/is/a/path

dla programistów C zajmujących się R, sprintf jest znany i przydatny do „łączenia dwóch łańcuchów”
napisano

O wiele lepszy imho. pastenie jest wystarczająco elastyczny, jeśli chcesz dołączyć coś do łańcucha.
nazwa wyświetlana

20

Możesz stworzyć własnego operatora:

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

Możesz także ponownie zdefiniować &operator „i” ( ):

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

mieszanie się ze składnią podstawową jest brzydkie, ale tak samo jest przy użyciu, paste()/paste0()jeśli pracujesz tylko z własnym kodem, możesz (prawie zawsze) zastąpić & andoperator logiczny *i powielać wartości logiczne zamiast używać logicznych „i”


@Richard Scriven może nie rozumiem, ale wydaje się proste, porównaj: paste0(as.matrix(iris[1:4]) , as.matrix(iris[1:4]))ias.matrix(iris[1:4]) %&% as.matrix(iris[1:4])
Qbik

bardzo, bardzo dobrze! & jest standardem dla konkatenacji w wielu językach, tak naprawdę uważam, że R powinien był to mieć domyślnie. zdecydowanie polecam w ten sposób
Serhii

14

Biorąc pod uwagę macierz, tmp, którą utworzyłeś:

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

Zakładam, że istnieje jakiś powód, dla którego tworzysz macierz za pomocą cbind, a nie po prostu:

tmp <- "GAD,AB"

3

Rozważ przypadek, w którym ciągi są kolumnami, a wynikiem powinna być nowa kolumna:

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

Opcjonalnie [c("a", "b")]możesz pominąć podzbiór, jeśli wszystkie kolumny wymagają wklejenia.

# 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, ale stringi, stringrbiblioteki są szybsze.
smci

2

Inna odpowiedź niepasująca:

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

Gdzie

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

2

glueto nowa funkcja, klasa danych i pakiet, który został opracowany w ramach tidyverse, z dużą ilością rozszerzonych funkcji. Łączy funkcje z wklejania, sprintf i poprzednich innych odpowiedzi.

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

Utworzono 2019-03-06 przez pakiet reprezentx (v0.2.1)

Tak, jest to przesada w przypadku prostego przykładu w tym pytaniu, ale potężny w wielu sytuacjach. (patrz https://glue.tidyverse.org/ )

Szybki przykład w porównaniu pastez withponiższym. TheglueKod był nieco łatwiejszy do pisania i wygląda nieco łatwiejsze do odczytania.

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."

Utworzono 2019-03-06 przez pakiet reprezentx (v0.2.1)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.