2013-06-09 12 views
29

mam listy ciągów znaków, które zawierają losowe, takie jak:Wyodrębnianie unikalne numery z ciągiem w R

list=list() 
list[1] = "djud7+dg[a]hs667" 
list[2] = "7fd*hac11(5)" 
list[3] = "2tu,g7gka5" 

Chciałbym wiedzieć, które numery są obecne co najmniej raz (unique()) na tej liście. Rozwiązanie moim przykładzie jest:

rozwiązanie: c(7,667,11,5,2)

Jeśli ktoś ma metodę, która nie bierze pod uwagę 11 jako „jedenastu”, ale jako „jeden plus jeden”, byłoby również użyteczne. Rozwiązaniem w takiej sytuacji może być:

rozwiązanie: c(7,6,1,5,2)

(Znalazłem ten artykuł na pokrewny temat: Extracting numbers from vectors of strings)

Odpowiedz

54

dla drugiej odpowiedzi, można użyć gsub usunąć wszystko z ciągiem to nie jest liczba, a następnie podzielić ciąg w następujący sposób:

unique(as.numeric(unlist(strsplit(gsub("[^0-9]", "", unlist(ll)), "")))) 
# [1] 7 6 1 5 2 

Dla pierwszej odpowiedzi, podobnie używając strsplit,

unique(na.omit(as.numeric(unlist(strsplit(unlist(ll), "[^0-9]+"))))) 
# [1] 7 667 11 5 2 

PS: nie nazwij swojej zmiennej list (ponieważ jest tam wbudowana funkcja list). Nazwałam twoje dane jako ll.

6

Można użyć ?strsplit (jak sugeruje @ odpowiedź Arun w Extracting numbers from vectors (of strings)):

l <- c("djud7+dg[a]hs667", "7fd*hac11(5)", "2tu,g7gka5") 

## split string at non-digits 
s <- strsplit(l, "[^[:digit:]]") 

## convert strings to numeric ("" become NA) 
solution <- as.numeric(unlist(s)) 

## remove NA and duplicates 
solution <- unique(solution[!is.na(solution)]) 
# [1] 7 667 11 5 2 
1

Zastosowanie strsplit stosując wzór jako odwrotność cyfr: 0-9

Dla przykładu podałeś , to zrobić:

tmp <- sapply(list, function (k) strsplit(k, "[^0-9]")) 

Następnie wystarczy wziąć zjednoczenie wszystkich `ustawia na liście, tak jak poniżej:

tmp <- Reduce(union, tmp) 

Następnie wystarczy usunąć pusty ciąg.

+0

Trzy identyczne odpowiedzi w minutach względem siebie! : D – asb

+0

'strsplit' jest wektorowy. Można/należy unikać używania pętli przez "niepublikowanie danych OP. – Arun

+0

Użycie 'Reduce' z' union' (jest w zasadzie pętlą) również będzie bardzo czasochłonne na wielkich listach ('unique' i' unlist' będzie znacznie szybsze). – Arun

15

Oto kolejna odpowiedź, tym razem przy użyciu gregexpr znaleźć numery i regmatches wyodrębnić je:

l <- c("djud7+dg[a]hs667", "7fd*hac11(5)", "2tu,g7gka5") 

temp1 <- gregexpr("[0-9]", l) # Individual digits 
temp2 <- gregexpr("[0-9]+", l) # Numbers with any number of digits 

as.numeric(unique(unlist(regmatches(l, temp1)))) 
# [1] 7 6 1 5 2 
as.numeric(unique(unlist(regmatches(l, temp2)))) 
# [1] 7 667 11 5 2 
4

stringr rozwiązanie z str_match_all oraz sprzęt operatorów.Dla pierwszego rozwiązania:

library(stringr) 
str_match_all(ll, "[0-9]+") %>% unlist %>% unique %>% as.numeric 

Drugie rozwiązanie:

str_match_all(ll, "[0-9]") %>% unlist %>% unique %>% as.numeric 

(Uwaga: Ja również nazywany listę ll)

7

Rozwiązanie korzystając stringi

# extract the numbers: 

nums <- stri_extract_all_regex(list, "[0-9]+") 

# Make vector and get unique numbers: 

nums <- unlist(nums) 
nums <- unique(nums) 

I to twoje pierwsze rozwiązanie

Screenshot from on-liner in R

Na drugim roztworze użyłbym substr:

nums_first <- sapply(nums, function(x) unique(substr(x,1,1))) 
+0

Skąd pochodzi "stri_extract_all_regex()"? –

+0

Pakiet stringi, tak jak napisano w tytule – altabq

1

Sprawdź funkcję extract_numbers() z pakietu filesstrings. Zainstaluj go przez install.packages("filesstrings").

library(filesstrings) 
#> Loading required package: stringr 
list=list() 
list[1] = "djud7+dg[a]hs667" 
list[2] = "7fd*hac11(5)" 
list[3] = "2tu,g7gka5" 
charvec <- unlist(list) 
print(charvec) 
#> [1] "djud7+dg[a]hs667" "7fd*hac11(5)"  "2tu,g7gka5" 
extract_numbers(charvec) 
#> [[1]] 
#> [1] 7 667 
#> 
#> [[2]] 
#> [1] 7 11 5 
#> 
#> [[3]] 
#> [1] 2 7 5 
unique(unlist(ExtractNumbers(charvec))) 
#> [1] 7 667 11 5 2