2012-12-07 72 views
7

Tôi có nhu cầu lấy tất cả ba hình tam giác nguyên tố tạo thành hình tam giác dưới của ma trận đối xứng. Tôi không thể nghĩ làm thế nào để lấy tất cả các mảnh theo thứ tự của cột trái xa làm việc xuống và sau đó cột tiếp theo bên phải và như vậy. Tôi biết rằng numbe ROF tam giác nhỏ bên trong của tam giác thấp hơn là:Lấy hình tam giác trong hình tam giác dưới

n = x(x - 1)/2 
where: x = nrow(mats[[i]]) 

Ở đây tôi đã tạo ba ma trận với chữ cái (nó dễ dàng hơn cho tôi để khái niệm hóa theo cách này) và các yếu tố theo thứ tự tôi tìm kiếm

FUN <- function(n) { 
    matrix(LETTERS[1:(n*n)], n) 
} 

mats <- lapply(3:5, FUN) 

vì vậy, đây là sản phẩm tôi muốn nhận được (tôi đặt nó trong mã chứ không phải là định dạng đầu ra) cho mỗi của các ma trận tạo ở trên:

list(c("B", "C", "F")) 

list(c("B", "C", "G"), c("C", "D", "H"), c("G", "H", "L")) 

list(c("B", "C", "H"), c("C", "D", "I"), c("D", "E", "J"), 
    c("H", "I", "N"), c("I", "J", "O"), c("N", "O", "T")) 

Làm thế nào tôi có thể làm t nhiệm vụ của mình theo cách nhanh nhất có thể khi ở tại cơ sở R?

Không chắc nếu điều này hình ảnh của những gì tôi là sau khi có hữu ích nhưng nó có thể là:

enter image description here

+0

Là một ma trận 5x5 lớn nhất mà bạn mong đợi để phải kiểm tra? –

+0

Không, nó có thể lớn hơn (mặc dù tôi rất nghi ngờ nó sẽ bao giờ lớn hơn nhiều). –

+0

@TylerRinker - Tôi chỉ phải bắt buộc đóng phiên R trong khi thử một số điểm chuẩn trên ma trận 10K * 10K. 1K * 1K chỉ là một vài giây. Tôi tự hỏi liệu mọi người có thể triển khai hiệu quả hơn không. – thelatemail

Trả lời

5

đẹp vấn đề! Đây là cách bạn có thể giải quyết nó bằng cách sử dụng một chút đệ quy (theo sau là một phiên bản đơn giản MUCH)

triangle <- function(base.idx, mat) { 
    upper.idx <- base.idx - 1L 
    right.idx <- base.idx + nrow(mat) 
    paste(mat[c(upper.idx, base.idx, right.idx)], collapse = " ") 
} 

get.triangles <- function(mat) { 
    N <- nrow(mat) 
    if (N == 3L) { 
     return(triangle(3L, mat)) 
    } else { 
     left.idx <- 3:N 
     right.mat <- mat[2:N, 2:N] 
     left.triangles <- sapply(left.idx, triangle, mat) 
     right.triangles <- Recall(right.mat) 
     return(c(left.triangles, right.triangles)) 
    } 
} 

x <- lapply(mats, get.triangles) 

# [[1]] 
# [1] "B C F" 
# 
# [[2]] 
# [1] "B C G" "C D H" "G H L" 
# 
# [[3]] 
# [1] "B C H" "C D I" "D E J" "H I N" "I J O" "N O T" 

Tôi sẽ chỉ bình luận về đầu ra không chính xác như bạn đã hỏi. Đó là bởi vì việc tạo ra các chức năng đệ quy mà trả về một danh sách phẳng luôn khó khăn để làm việc với: bằng cách nào đó bạn luôn kết thúc với danh sách lồng nhau ...

Vì vậy, bước cuối cùng nên là:

lapply(x, strsplit, split = " ") 

và nó sẽ ở cùng định dạng mà bạn yêu cầu.


Và đây là một phiên bản đơn giản (quên về đệ quy!)

get.triangles <- function(mat) { 
    base.idx <- seq_along(mat)[row(mat) > col(mat) + 1] 
    upper.idx <- base.idx - 1L 
    right.idx <- base.idx + nrow(mat) 

    lapply(mapply(c, upper.idx, base.idx, right.idx, SIMPLIFY = FALSE), 
      function(i)mat[i]) 
} 
+0

cảm ơn bạn hoạt động rất độc đáo. Tôi sẽ sử dụng phương thức mà không cần đệ quy vì không cần sử dụng 'strsplit' (và nếu nó là ma trận số không cần sử dụng' as.numeric'). +1 –

3

Edited để thêm một SIMPLIFY=FALSE mà hiện nay mang lại cho chính xác những gì bạn muốn:

Về cơ bản, phương pháp này được các các chỉ mục của tất cả các góc trên cùng bên trái của tam giác mà bạn muốn và sau đó lấy [ô bên dưới] + [ô bên dưới + bên phải]. Hồi hộp. Một lợi ích bổ sung của phương pháp này là nó hoạt động cho các đối tượng matrixdata.frame.

bot.tris <- function(data) { 
    idx1 <- unlist(sapply((nrow(data)-2):1,function(x) tail(2:(nrow(data)-1),x))) 
    idx2 <- rep(1:(nrow(data)-2),(nrow(data)-2):1) 
    mapply(function(x,y) {c(data[x,y],data[x+1,y],data[x+1,y+1])},idx1,idx2,SIMPLIFY=FALSE) 
} 

Và kết quả:

> result <- lapply(mats,bot.tris) 
> str(result) 
List of 3 
$ :List of 1 
    ..$ : chr [1:3] "B" "C" "F" 
$ :List of 3 
    ..$ : chr [1:3] "B" "C" "G" 
    ..$ : chr [1:3] "C" "D" "H" 
    ..$ : chr [1:3] "G" "H" "L" 
$ :List of 6 
    ..$ : chr [1:3] "B" "C" "H" 
    ..$ : chr [1:3] "C" "D" "I" 
    ..$ : chr [1:3] "D" "E" "J" 
    ..$ : chr [1:3] "H" "I" "N" 
    ..$ : chr [1:3] "I" "J" "O" 
    ..$ : chr [1:3] "N" "O" "T" 
+1

Cách tiếp cận này chắc chắn ít mã hóa và rất dễ hiểu.Tôi đã đánh giá cả hai câu trả lời và flodel là nhanh hơn. Cả hai chức năng ở đây đều nhanh hơn những gì tôi có (không có gì). Cảm ơn bạn rất nhiều vì đã giải quyết vấn đề. +1 –

+0

* "Cả hai chức năng ở đây đều nhanh hơn những gì tôi có (không có gì)" * - Tôi thích điều đó :-) – thelatemail

Các vấn đề liên quan