2015-03-03 14 views
6

Użyłem adist obliczyć liczbę znaków, które różnią się między dwa ciągi:Wyciąg znaków, które różnią się między dwa ciągi

a <- "Happy day" 
b <- "Tappy Pay" 
adist(a,b) # result 2 

Teraz chciałbym, aby wyodrębnić te postaci, które różnią. W moim przykładzie chciałbym uzyskać ciąg znaków "Hd" (lub "TP", to nie ma znaczenia).

Próbowałem szukać w adist, agrep i stringi, ale niczego nie znalazłem.

+2

Proponuję cofnąć edycję i zadać nowe pytania tację. W tym nowym pytaniu będziesz musiał podać znacznie więcej informacji o swoich prawdziwych danych. Na przykład bardzo ważne jest, czy wiesz, że różne ciągi są na początku, czy na końcu łańcucha. Musisz również poinformować nas, jeśli Twój problem w ogóle odnosi się do [najdłuższego wspólnego problemu z podciąganiu] (http://en.wikipedia.org/wiki/Longest_common_substring_problem). – Andrie

+1

Uzgodniono, cofnij edycję, zaakceptuj najlepszą odpowiedź i zadaj nowe pytanie.Pytanie jest zasadniczo odmienne, a wiele osób już włożyło dużo pracy. – BrodieG

Odpowiedz

12

Można użyć następującej sekwencji operacji:

  • Podziel ciąg znaków za pomocą strsplit().
  • Zastosowanie setdiff() porównać elementy
  • owijane w funkcji redukującej

Spróbuj tego:

Reduce(setdiff, strsplit(c(a, b), split = "")) 
[1] "H" "d" 
+5

To degeneruje się do kodu golfowego, prawda? :) – Spacedman

+0

'do.call (setdiff, strsplit (c (a, b), split =" "))) będzie prawdopodobnie bardziej wydajny –

+0

Drugi argument dla' strsplit' to 'split', więc nie musisz wymieniać nazwy jeśli chcesz uzyskać mniejszą liczbę strzałów. – Spacedman

1

Dopóki a i b mają taką samą długość możemy to zrobić:

s.a <- strsplit(a, "")[[1]] 
s.b <- strsplit(b, "")[[1]] 
paste(s.a[s.a != s.b], collapse = "") 

dawanie:

[1] "Hd" 

To wydaje się proste pod względem czytelności kodu i wydaje wiązanej dla najszybsze z podanych tu rozwiązań, chociaż myślę, że wolę f3:

f1 <- function(a, b) 
    paste(setdiff(strsplit(a,"")[[1]],strsplit(b,"")[[1]]), collapse = "") 

f2 <- function(a, b) 
    paste(sapply(setdiff(utf8ToInt(a), utf8ToInt(b)), intToUtf8), collapse = "") 

f3 <- function(a, b) 
    paste(Reduce(setdiff, strsplit(c(a, b), split = "")), collapse = "") 

f4 <- function(a, b) { 
    s.a <- strsplit(a, "")[[1]] 
    s.b <- strsplit(b, "")[[1]] 
    paste(s.a[s.a != s.b], collapse = "") 
} 

a <- "Happy day" 
b <- "Tappy Pay" 

library(rbenchmark) 
benchmark(f1, f2, f3, f4, replications = 10000, order = "relative")[1:4] 

podając następujące na świeżym sesji na moim laptopie:

test replications elapsed relative 
3 f3  10000 0.07 1.000 
4 f4  10000 0.07 1.000 
1 f1  10000 0.09 1.286 
2 f2  10000 0.10 1.429 

mam przyjąć, że różnice muszą być w odpowiednich pozycjach znaków. Możesz wyjaśnić, czy to jest intencja, czy nie.

4

Nie bardzo dumny z tego, ale wydaje się, aby wykonać zadanie:

sapply(setdiff(utf8ToInt(a), utf8ToInt(b)), intToUtf8) 

wyniki:

[1] "H" "d" 
+4

To miło. Prawdopodobnie można go wektoryzować za pomocą 'intToUtf8 (setdiff (utf8ToInt (a), utf8ToInt (b)))' –

7

podzielone na litery i wziąć różnicę jako zestawy:

> setdiff(strsplit(a,"")[[1]],strsplit(b,"")[[1]]) 
[1] "H" "d" 
2

Można użyć jednej ze zmiennych jak regex klasy postaci i gsub się z inny:

gsub(paste0("[",a,"]"),"",b) 
[1] "TP" 
gsub(paste0("[",b,"]"),"",a) 
[1] "Hd" 
+0

Czy to działa, jeśli łańcuchy mają wyrazy regularne - Specjalne znaki w nich? – Spacedman

+0

@Spacedman Tak, dobry połów, specjalne wyrażenie klasy regex, takie jak '^' i '-' może powodować problemy. Może to być szczególny problem z łączonymi wyrazami. – James