2013-06-09 18 views
29

Tôi có một danh sách các chuỗi có chứa ký tự ngẫu nhiên như:Extracting con số duy nhất từ ​​chuỗi trong R

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

Tôi muốn biết số điện thoại nào có mặt ít nhất một lần (unique()) trong danh sách này. Các giải pháp của ví dụ của tôi là:

giải pháp: c(7,667,11,5,2)

Nếu ai đó có một phương pháp mà không xem xét 11 như "mười một", nhưng là "một trong và một", nó sẽ còn có ích. Các giải pháp trong tình trạng này sẽ là:

giải pháp: c(7,6,1,5,2)

(Tôi tìm thấy bài viết này về một chủ đề liên quan: Extracting numbers from vectors of strings)

Trả lời

54

Đối với câu trả lời thứ hai, bạn có thể sử dụng gsub để loại bỏ tất cả mọi thứ từ chuỗi đó không phải là một con số, sau đó chia chuỗi như sau:

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

Đối với câu trả lời đầu tiên, tương tự như sử dụng strsplit,

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

PS: không đặt tên biến của bạn list (vì có chức năng sẵn có list). Tôi đã đặt tên cho dữ liệu của bạn là ll.

6

Bạn có thể sử dụng ?strsplit (như đề xuất trong @ Arun của câu trả lời trong 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

Sử dụng strsplit sử dụng mô hình như là nghịch đảo của ký tự số: 0-9

Ví dụ bạn đã cung cấp , làm điều này:

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

Sau đó chỉ cần mất một đoàn của tất cả các 'đặt trong danh sách, như vậy:

tmp <- Reduce(union, tmp) 

Sau đó, bạn chỉ phải xóa chuỗi rỗng.

+0

Ba câu trả lời giống nhau trong một phút của nhau! : D – asb

+0

'strsplit' được vectơ hóa. Bạn có thể/nên tránh sử dụng các vòng bằng cách 'không liệt kê dữ liệu của OP. – Arun

+0

Sử dụng 'Reduce' với' union' (về bản chất là looping) ở đây cũng sẽ tốn rất nhiều thời gian cho các danh sách lớn ('unique' và' unlist' sẽ nhanh hơn nhiều). – Arun

15

Dưới đây là câu trả lời khác được nêu ra, chương trình này sử dụng gregexpr để tìm các con số, và regmatches để trích xuất chúng:

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

Một giải pháp stringr với str_match_all và được truyền dẫn các nhà khai thác.Đối với giải pháp đầu tiên:

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

giải pháp thứ hai:

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

(Lưu ý: Tôi cũng được gọi là danh sách ll)

7

Một giải pháp sử dụng stringi

# extract the numbers: 

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

# Make vector and get unique numbers: 

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

Và đó là giải pháp đầu tiên của bạn

Screenshot from on-liner in R

Đối với giải pháp thứ hai tôi sẽ sử dụng substr:

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

'stri_extract_all_regex()' xuất phát từ đâu? –

+0

Gói stringi, giống như trong tiêu đề – altabq

1

Kiểm tra các extract_numbers() chức năng từ gói filesstrings. Cài đặt nó qua 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