2017-01-06 13 views
9

Tôi đang cố gắng tìm xem có cách nào nhanh chóng tìm kiếm các chuỗi cụ thể trong mảng trong R hay không, giống như trò chơi Boggle, ngoại trừ bạn biết từ trả trước.Tìm chuỗi cụ thể trong một mảng bằng cách sử dụng R

Bạn được phép di chuyển theo hướng sau cho chữ cái tiếp theo của chuỗi: lên, xuống, sang phải hoặc trái

Nói cho một ví dụ đơn giản, bạn có một loạt các hình thức:

> G  
A, Q, A, Q, Q, 
A, Q, P, Q, Q, 
Q, Q, P, L, Q, 
Q, Q, Q, E, Q 

Và bạn muốn áp dụng hàm G với chuỗi APPLE, để hàm trả về TRUE, APPLE tồn tại trong mảng này và FALSE nếu không.

Có tồn tại một chức năng hoặc gói được tạo sẵn có thể thực hiện điều này hay không, hoặc có cách thông minh để làm điều đó, tôi tương đối mới để xử lý chuỗi trong R và tôi đang cố gắng để xem một cách .

Bất kỳ trợ giúp nào được đánh giá cao. Cảm ơn.

+1

Chào mừng bạn đến với StackOverflow. Hãy xem các mẹo này về cách tạo ra [ví dụ tối thiểu, đầy đủ và có thể xác minh được] (http://stackoverflow.com/help/mcve), cũng như bài đăng này trên [tạo một ví dụ tuyệt vời trong R] (http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example).Có lẽ những lời khuyên sau đây về [hỏi một câu hỏi hay] (http://stackoverflow.com/help/how-to-ask) cũng có thể đáng đọc. – lmo

+4

không bao giờ nghĩ đến việc viết mã cho trò chơi trong R! :) –

Trả lời

2

đầu tiên này sẽ kiểm tra nếu có bất kỳ nhân vật trong văn bản của bạn không tồn tại trong mảng và sau đó sẽ kiểm tra nếu số lượng ký tự trong mảng là đủ để đáp ứng chữ lặp lại trong văn bản của bạn

word <- strsplit("APPLE", "") 
pool <- c("A", "Q", "A", "Q", 
      "Q", "A", "Q", "P", 
      "Q", "Q", "Q", "Q", 
      "P", "L", "Q", "Q", 
      "Q", "Q", "E", "Q") 

t.word <- table(word) 
t.pool <- table(pool) 

length(setdiff(names(t.word), names(t.pool))) == 0 
min(t.pool[names(t.word)] - t.word) >= 0 

hai chức năng cuối cùng sẽ cả sản lượng TRUE để chứng minh rằng tất cả các chữ cái từ word tồn tại trong pool và rằng số lượng của một chữ cái trong word là không lớn so với pool

ở dạng hàm sẽ ra TRUE nếu tìm thấy, nếu không FALSE

word.find <- function(word, pool) { 
    t.word <- table(strsplit(word, "")) 
    t.pool <- table(pool) 
    length(setdiff(names(t.word), names(t.pool))) == 0 & min(t.pool[names(t.word)] - t.word) >= 0 
} 

word.find("APPLE", pool) 
[1] TRUE 

word.find("APPLES", pool) 
[1] FALSE 

word.find("APPLEE", pool) 
[1] FALSE 
2

chức năng này hoạt động chỉ sử dụng cơ sở R

CHỨC NĂNG

search_string = function(matrix_array, word_to_search){ 

    position = data.frame(NA,NA,NA) #Create empty dataframe 

    word_to_search_inv = sapply(lapply(strsplit(word_to_search, NULL), rev), paste, collapse="") #Reverse word_to_search 

    for (i in 1:nrow(matrix_array)){ 
     str_row = paste((matrix_array[i,]),collapse = "") #Collapse entire row into a string 
     if (grepl(word_to_search,str_row)) { #Check if the word_to_search is in the string towards right 
      position = rbind(position,c(i,paste(gregexpr(word_to_search, str_row)[[1]], collapse = ', '),"RIGHT")) #Get position and add it to the dataframe  
     } 
     if (grepl(word_to_search_inv,str_row)) {#Check if the word_to_search is in the string towards left (by checking for reverse of word_to_search) 
      position = rbind(position,c(i,paste(gregexpr(word_to_search_inv, str_row)[[1]], collapse = ', '),"LEFT"))  
     } 
    } 

    for (j in 1:ncol(matrix_array)){   
     str_column = paste((matrix_array[,j]),collapse = "") 
     if (grepl(word_to_search, str_column)) { #Check if the word_to_search is in the string towards down 
      position = rbind(position, c(paste(gregexpr(word_to_search, str_column)[[1]], collapse = ', '),j,"DOWN")) 
     } 
     if (grepl(word_to_search_inv, str_column)) { #Check if the word_to_search is in the string towards up 
      position = rbind(position, c(paste(gregexpr(word_to_search_inv, str_column)[[1]], collapse = ', '),j,"UP")) 
     } 
    } 

    colnames(position) = c("ROW","COLUMN","DIRECTION") 
    position = position[c(2:nrow(position)),] 
    rownames(position) = NULL 
    return(position) #Return the datafram containing row, columnm, and direction where word_to_match is found 
} 

SỬ DỤNG

#Data 
mydata = structure(c("A", "A", "Q", "Q", "D", "Q", "Q", "Q", "Q", "B", 
        "A", "P", "P", "L", "E", "Q", "Q", "L", "E", "S", "Q", "Q", "Q", 
        "Q", "T", "A", "P", "P", "L", "E"), .Dim = c(5L, 6L), .Dimnames = list(NULL, c("V1", "V2", 
                      "V3", "V4", "V5", "V6"))) 

key = "APPLE" 

#Run the function 
pos = search_string(mydata,key) 
+0

Cảm ơn cả hai. Điều này có tác dụng nếu từ này nằm trong một đường thẳng, nhưng không nếu từ "di chuyển các góc tròn", bạn có biết cách để làm điều này không? – user2915209

1

Thêm cách tiếp cận khác, có:

board = structure(c("A", "A", "Q", "Q", "Q", "Q", "Q", "Q", "A", "P", 
"P", "Q", "Q", "Q", "L", "E", "Q", "Q", "Q", "Q"), .Dim = 4:5, .Dimnames = list(
    NULL, NULL)) 

word = "APPLE" 

chúng ta bắt đầu với:

matches = lapply(strsplit(word, NULL)[[1]], function(x) which(x == board, arr.ind = TRUE)) 

mà là một đơn giản tìm kiếm -probably unavoidable- của chỉ số của "ban" phù hợp với từng chữ cái của từ này. Đó là một "danh sách" có chứa các chỉ số hàng/col như:

#[[1]] 
#  row col 
#[1,] 1 1 
#[2,] 2 1 
#[3,] 1 3 
# 
#[[2]] 
#  row col 
#[1,] 2 3 
#[2,] 3 3 
# 
##..... 

Có đó, chúng ta cần phải tìm hiểu, dần dần, cho dù một chỉ số trong mỗi phần tử có một người hàng xóm (tức là phải/trái/lên/xuống ô) trong phần tử tiếp theo. Ví dụ.chúng ta cần cái gì đó như:

as.matrix(find_neighbours(matches[[1]], matches[[2]], dim(board))) 
#  [,1] [,2] 
#[1,] FALSE FALSE 
#[2,] FALSE FALSE 
#[3,] TRUE FALSE 

mà chúng ta biết, rằng hàng 3 matches[[1]] là một người hàng xóm của hàng 1 trong tổng số matches[[2]], ví dụ: [1, 3][2, 3] là, quả thật vậy, các tế bào lân cận. Chúng tôi cần điều này cho mỗi phần tử liên tiếp trong "trận đấu":

are_neighs = Map(function(x, y) which(find_neighbours(x, y, dim(board)), TRUE), 
       matches[-length(matches)], matches[-1]) 
are_neighs 
#[[1]] 
#  [,1] [,2] 
#[1,] 3 1 
# 
#[[2]] 
#  [,1] [,2] 
#[1,] 2 1 
#[2,] 1 2 
# 
#[[3]] 
#  [,1] [,2] 
#[1,] 2 1 
# 
#[[4]] 
#  [,1] [,2] 
#[1,] 1 1 

Bây giờ chúng ta có cặp ("i" với "i + 1") hàng xóm phù hợp chúng ta cần phải hoàn thành chuỗi. Đối với ví dụ này, chúng tôi muốn có một vectơ như c(1, 2, 1, 1) chứa thông tin rằng hàng 1 của are_neighs[[1]] bị xích với hàng 2 của are_neighs[[2]] bị xích với hàng 1 của are_neighs[[3]] bị xích với hàng 1 của are_neighs[[4]]. Đây có mùi giống như một "igraph" vấn đề, nhưng tôi không quá quen thuộc với nó (hy vọng ai đó có một ý tưởng tốt hơn), vì vậy đây là một cách tiếp cận ngây thơ để nhận được rằng chaining:

row_connections = matrix(NA_integer_, nrow(are_neighs[[1]]), length(are_neighs)) 
row_connections[, 1] = 1:nrow(are_neighs[[1]]) 
cur = are_neighs[[1]][, 2] 
for(i in 1:(length(are_neighs) - 1)) { 
    im = match(cur, are_neighs[[i + 1]][, 1]) 
cur = are_neighs[[i + 1]][, 2][im] 
row_connections[, i + 1] = im 
} 
row_connections = row_connections[complete.cases(row_connections), , drop = FALSE] 

nào trả về:

row_connections 
#  [,1] [,2] [,3] [,4] 
#[1,] 1 2 1 1 

có vector này, bây giờ, chúng ta có thể trích xuất các chuỗi tương ứng từ "are_neighs":

Map(function(x, i) x[i, ], are_neighs, row_connections[1, ]) 
#[[1]] 
#[1] 3 1 
# 
#[[2]] 
#[1] 1 2 
# 
#[[3]] 
#[1] 2 1 
# 
#[[4]] 
#[1] 1 1 

mà có thể được sử dụng để trích xuất các chuỗi hàng/col phù hợp của các chỉ số từ "trận đấu":

ans = vector("list", nrow(row_connections)) 
for(i in 1:nrow(row_connections)) { 
    connect = Map(function(x, i) x[i, ], are_neighs, row_connections[i, ]) 
    ans[[i]] = do.call(rbind, Map(function(x, i) x[i, ], matches, c(connect[[1]][1], sapply(connect, "[", 2)))) 
} 
ans 
#[[1]] 
#  row col 
#[1,] 1 3 
#[2,] 2 3 
#[3,] 3 3 
#[4,] 3 4 
#[5,] 4 4 

Bao bì nó tất cả trong một hàm (find_neighbours được định nghĩa bên trong):

library(Matrix) 
ff = function(word, board) 
{ 
    matches = lapply(strsplit(word, NULL)[[1]], function(x) which(x == board, arr.ind = TRUE)) 

    find_neighbours = function(x, y, d) 
    { 
     neighbours = function(i, j, d = d) 
     { 
      ij = rbind(cbind(i, j + c(-1L, 1L)), cbind(i + c(-1L, 1L), j)) 
      ijr = ij[, 1]; ijc = ij[, 2] 
      ij = ij[((ijr > 0L) & (ijr <= d[1])) & ((ijc > 0L) & (ijc <= d[2])), ] 

      ij[, 1] + (ij[, 2] - 1L) * d[1] 
     } 

     x.neighs = lapply(1:nrow(x), function(i) neighbours(x[i, 1], x[i, 2], dim(board))) 
     y = y[, 1] + (y[, 2] - 1L) * d[1] 

     x.sparse = sparseMatrix(i = unlist(x.neighs), 
           j = rep(seq_along(x.neighs), lengths(x.neighs)), 
           x = 1L, dims = c(prod(d), length(x.neighs))) 
     y.sparse = sparseMatrix(i = y, j = seq_along(y), x = 1L, dims = c(prod(d), length(y)))       

     ans = crossprod(x.sparse, y.sparse, boolArith = TRUE) 

     ans 
    }  

    are_neighs = Map(function(x, y) which(find_neighbours(x, y, dim(board)), TRUE), matches[-length(matches)], matches[-1]) 

    row_connections = matrix(NA_integer_, nrow(are_neighs[[1]]), length(are_neighs)) 
    row_connections[, 1] = 1:nrow(are_neighs[[1]]) 
    cur = are_neighs[[1]][, 2] 
    for(i in 1:(length(are_neighs) - 1)) { 
     im = match(cur, are_neighs[[i + 1]][, 1]) 
     cur = are_neighs[[i + 1]][, 2][im] 
     row_connections[, i + 1] = im 
    } 
    row_connections = row_connections[complete.cases(row_connections), , drop = FALSE] 

    ans = vector("list", nrow(row_connections)) 
    for(i in 1:nrow(row_connections)) { 
     connect = Map(function(x, i) x[i, ], are_neighs, row_connections[i, ]) 
     ans[[i]] = do.call(rbind, Map(function(x, i) x[i, ], matches, c(connect[[1]][1], sapply(connect, "[", 2)))) 
    } 
    ans 
} 

Chúng tôi có thể thử nó:

ff("APPLE", board) 
#[[1]] 
#  row col 
#[1,] 1 3 
#[2,] 2 3 
#[3,] 3 3 
#[4,] 3 4 
#[5,] 4 4 

Và với nhiều hơn một trận đấu:

ff("AQQP", board) 
#[[1]] 
#  row col 
#[1,] 1 1 
#[2,] 1 2 
#[3,] 2 2 
#[4,] 2 3 
# 
#[[2]] 
#  row col 
#[1,] 1 3 
#[2,] 1 2 
#[3,] 2 2 
#[4,] 2 3 
# 
#[[3]] 
#  row col 
#[1,] 1 3 
#[2,] 1 4 
#[3,] 2 4 
#[4,] 2 3 

Mặc dù, nó linh hoạt trong việc trả về nhiều kết quả phù hợp, nó không trả về tất cả các kết quả phù hợp và tóm lại, đó là vì việc sử dụng match khi xây dựng chuỗi các hàng xóm - một tìm kiếm tuyến tính có thể được sử dụng thay thế. phức tạp.

0

Tôi đã viết bên dưới và nó hoạt động tốt và nhanh chóng, cũng như được dịch sang bất kỳ ngôn ngữ nào khác. Với một đồ thị G, và một từ điển, nó tìm kiếm thông qua từ điển và sau đó kiểm tra xem G có bất kỳ chữ cái nào tương ứng với chữ cái thứ nhất của mỗi từ mà nó cần kiểm tra hay không. Tiếp theo, nó kiểm tra xem có bất kỳ hàng xóm nào, được tìm thấy bởi các chỉ số giá trị TRUE + delta, của các giá trị TRUE của các giá trị trước đó bằng 2 của từ đó. Và điều này tiếp tục.

Nếu tại bất kỳ thời điểm nào được tìm thấy không phải là TRUE, hàm kết thúc và trả về FALSE. Ngoài ra, nếu bạn sắp xếp từ điển của bạn bằng cách "hiếm" của các kết hợp thư, chức năng sẽ làm việc nhanh hơn nhiều.

#function to check if a word appears in a graph 
dict_check <- function(dictionary, G) { 

#Run thru dictionary and check if word is G 
#If at any point after a word check, it doesn't appear, break and return FALSE 

n <- length(dictionary) 
count_1 <- 0 #sum of words checked 
count_2 <- 0 #sum of words successfully found 
delta <- matrix(c(-1, 0, 1, 0, 
        0, -1, 0, 1), 
        byrow = T, nrow = 4, ncol = 2) 

for (dc in 1:n) { 
word <- dictionary[dc] 

#Add 1 for each word checked 
count_1 <- count_1 + 1 

#Split word into a vector 
W <- unlist(strsplit(word, "")) 

#Boolean matrix for 1st letter of word, if not there, end and return False 
G_bool <- G == W[1] 
if(sum(G_bool) == 0) { 
    return(FALSE) 
} 

#Fetch indices of True values for 1st letter of word 
I <- which(G_bool == T, arr.ind = T) 

#Loop thru word and check if neighbours match next letter of word, 
#for all letters of word 
#if at any point after iteration of a letter in word whereby G is all False, 
#return False for word_check 

last <- length(W) 
for (w in 2:last) { 

    #For each index in I, check if wordbox range, 
    #and check if neighbours ar equal to W[2, ...] 
    for (i in 1:nrow(I)) { 
    for (d in 1:nrow(delta)) { 
     #neighbour 
     k <- I[i, ] + delta[d, ] 

     #If neighbour is out of bounds of box then move onto next neighbour 
     #Each valid neighbour checked if is equal to next letter of word 
     #If it is equal set to neighbour to TRUE, and original position to FALSE 
     #If neighbour doesn't equal next letter, make original position FALSE anyway 
     G_bool[I[i, 1], I[i, 2]] <- FALSE #Set original position to FALSE 
     if (k[1] == 0 | k[1] > nrow(G) | k[2] == 0 | k[2] > ncol(G)) { 
     next} else if (G[k[1], k[2]] == W[w]) { 
      G_bool[k[1], k[2]] <- TRUE #Set neighbour to TRUE 
     } 
     } 
    } 
    #Check after each iteration of letter if any letters of subsequent 
    #letters appear, if yes, continue to next letter of word, if no, return 
    #FALSE for word check 
    if (sum(G_bool) == 0) { 
     return(FALSE) 
    } 
    #Update indices I for next TRUE in G_bool, corresponding to next letters found 
    I <- which(G_bool == T, arr.ind = T) 
    } 
    #Final check after word iteration is complete on G_bool 
    if (sum(G_bool) == 0) { 
    return(FALSE) 
    } else if (sum(G_bool) > 0) { 
    count_2 <- count_2 + 1 #Add 1 to count_2 if word successfully found 
    } 
    if (count_1 != count_2) { 
    return(FALSE) 
    } 
    } 
    #Final check 
    if (count_1 != count_2) { 
    return(FALSE) 
    } else 
    return(TRUE) 
    } 
Các vấn đề liên quan