2012-12-07 26 views
7

Simetrik matrisin alt üçgenini oluşturan üç element üçgenini yakalamama ihtiyacım var. Tüm bu parçaları nasıl en soldaki sütun sırasına göre sırayla ve sonra bir sonraki sütunu sağa vb. Ben alt üçgenin iç numbe rof küçük üçgenler olduğunu biliyoruz:Alt üçgen içindeki üçgenleri yakala

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

ben değilim sırayla harfler (benim bu şekilde conceptualize daha kolaydır) ve elemanları ile üç matrisleri oluşturduk Aradığınız:

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")) 

Nasıl olabilir:

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

mats <- lapply(3:5, FUN) 

Yani bu yukarıda oluşturulan matrislerin her biri için (daha doğrusu çıkış biçimi daha kodunda koymak) almak istiyorum çıkışı t yapmak R'de kalırken görevini en hızlı şekilde mümkün mü?

faydalı olanı Peşinde olduğum bu görsel emin ama olabilir değil:

enter image description here

+0

beklediğiniz o büyük test etmek için bir 5x5 matris midir? –

+0

Hayır daha büyük olabilirdi (yine de çok daha büyük olacağından kuşkuluyum). –

+0

@TylerRinker - Sadece 10K * 10K matrisinde bazı kıyaslama yaparken, R oturumumu kapatmaya zorlamak zorunda kaldım. 1K * 1K, birkaç saniye meselesiydi. Dışarıdaki insanların daha verimli uygulamalara sahip olup olmadıklarını merak ediyorum. – thelatemail

cevap

5

Güzel problem! Burada ben sadece istediğin gibi çıktı tam olmama konusunda yorum edeceğiz (çok daha basit versiyonu ardından) özyinelemeye biraz

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" 

kullanarak bunu çözebilir nasıl.

lapply(x, strsplit, split = " ") 

ve irade: nedense hep iç içe listeleri ile bitirmek

Yani son adımı olmalıdır ...: Düz listesini döndürür hep çalışmak zordur özyinelemeli fonksiyonlar yaratmak çünkü öyle İstediğiniz formatta olun.


Ve burada daha basit bir sürümü (özyineleme unutun!) 'Dir

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

teşekkürler çok güzel çalışıyor. 'Strsplit' kullanılmasına gerek olmadığından (ve eğer 'as.numeric' kullanılmasına gerek duyulmayan sayısal bir matrisse), metodu yineleme olmadan kullanacağım. +1 –

3

Düzenlendi şimdi tam olarak ne istediğinizi veren bir SIMPLIFY=FALSE eklemek için:

Temelde, bu yöntem alır Üçgenlerin sol üst köşelerinin tüm dizinlerini ve ardından [hücrenin altındaki] + [hücreyi + sağ altta] yakalar. Heyecan. Bu yöntemin bir yararı, matrix ve data.frame nesneler için çalışmasıdır.

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) 
} 

Ve sonuç:

> 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

Bu yaklaşım kesinlikle daha az kodlama ve anlaşılması çok kolay.Her iki yanıtı da karşılaştırdım ve flodel daha hızlı. Burada her iki işlev de sahip olduğumdan daha hızlıdır (hiçbir şey). Sorunu çözmek için çok teşekkür ederim. +1 –

+0

* "Her iki işlevde sahip olduğumdan daha hızlı (hiçbir şey)" * - Bunu beğendim :-) – thelatemail