簡體   English   中英

根據特定字符順序按字典順序對字符串進行排序

[英]Sorting strings lexicographically based upon certain character order

我正在努力解決 Rosalind 問題,並且陷入了Ordering Strings of Varying Length Lexicographically問題。

到目前為止,我已經成功地創建了不同長度字母的所有正確排列。 現在的主要問題是如何根據字母提供的順序對它們進行排序。

示例輸入是字母DNA 但在 n <= 4 個排列中最多可以有 12 個唯一字母。

對於示例 n = 3。這會產生 39 種不同的重復排列,但這些排列隨后將按照DNA之前的順序按字典順序排序。

這意味着正確的順序是:

正確的 不正確
一種
DD AA
DDD AAA級
專線專線 AAD
DDA 安聯
DN 廣告
免打擾 艾達
神經網絡 添加
脫氧核糖核酸 自動駕駛網絡
一個
爸爸 全日空
DAA 人工神經網絡
... ...
AAD 新南威爾士州
安聯 NND
AAA級 神經網絡

我的第一個想法是將它們轉換為具有水平的因素,然后嘗試根據它們的水平對它們進行排序,但我不能完全做到這一點。

到目前為止,我創建了所有排列的列表,然后嘗試對其進行排序,但不知道如何讓排序遵循給定的DNA順序

text_input <- c("D", "N", "A")
n <- 3

empty_df <- data.frame(matrix("", ncol = n))

temp_df <- data.frame()

for (i in n:1) {
  temp_df <- data.frame(arrangements::permutations(text_input, k = i, replace = TRUE))
  empty_df <- bind_rows(empty_df, temp_df)
}

result_df <- replace(empty_df, is.na(empty_df), "") |> 
  unite(col = combined, everything(), sep = "", remove = FALSE) |> 
  mutate(across(2:(n+2), ~ factor(.x, levels = text_input)),
         across(2:(n+2), ~ str_replace_na(.x, replacement = "")))

result_vec <- tail(result_df$combined, -1)

我將使用您擁有的樣本數據, Correct的,隨機的,以確保我們得到正確的順序。

quux <- structure(list(Correct = c("D", "DD", "DDD", "DDN", "DDA", "DN", "DND", "DNN", "DNA", "DA", "DAD", "DAN", "DAA", "AAD", "AAN", "AAA"), Incorrect = c("A", "AA", "AAA", "AAD", "AAN", "AD", "ADA", "ADD", "ADN", "AN", "ANA", "AND", "ANN", "NNA", "NND", "NNN")), row.names = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 15L, 16L, 17L), class = "data.frame")
set.seed(42)
quuxR <- quux[sample(nrow(quux)),]
quuxR$Correct
#  [1] "D"   "DDA" "AAA" "DNA" "DA"  "DDN" "DD"  "AAD" "DNN" "DND" "DAD" "DAA" "AAN" "DAN" "DDD" "DN" 

ltrs <- c("D", "N", "A")
inds <- lapply(strsplit(quux$Correct, ""), match, table = ltrs)
inds <- lapply(inds, `length<-`, max(lengths(inds)))
quuxR$Correct[do.call(order, c(do.call(Map, c(f=c, inds)), list(na.last = FALSE)))]
#  [1] "D"   "DD"  "DDD" "DDN" "DDA" "DN"  "DND" "DNN" "DNA" "DA"  "DAD" "DAN" "DAA" "AAD" "AAN" "AAA"
identical(quux$Correct, quuxR$Correct[do.call(order, c(do.call(Map, c(f=c, inds)), list(na.last = FALSE)))])
# [1] TRUE

腳步:

  1. strsplit(.., "")將字符串拆分為單個字母。
  2. match(.., table=ltrs)ltrs中的索引替換一個字母,這給了我們正確的字母優先級/排序。
  3. `length<-`是因為我們隨后將對它們進行rbind ,但這只有在它們都具有相同的長度時才有效。 執行此步驟(與max(lengths(..))一起使用NA填充較短的向量,以便所有子向量具有相同數量的元素。
  4. do.call(Map, c(f=c, inds))將長度為nm個向量列表轉置為長度為n的列表,每個列表都有m個元素。 這對下一步非常有幫助......
  5. do.call(order, ..)類似於調用order(L[[1]], L[[2]], L[[3]]) (如果L是轉置列表),但更具編程性。 我們將list(na.last=FALSE)作為參數添加到向量列表中,以便我們可以獲得較短字符串的正確排序。

您可以使用chartr並對其結果進行order ,並使用它來對原始無序向量進行子集化。

x <- c("DD", "AAN", "DDD", "DNA", "DAA", "DAD", "DDN", "DDA", "DND", 
       "DAN", "DNN", "DA", "AAA", "AAD", "DN", "D") #Unordered
y <- c("D", "DD", "DDD", "DDN", "DDA", "DN", "DND", "DNN", "DNA", "DA",
       "DAD", "DAN", "DAA", "AAD", "AAN", "AAA") #Target order

z <- x[order(chartr("DNA", "ABC", x))]
identical(z, y)
#[1] TRUE

z
# [1] "D"   "DD"  "DDD" "DDN" "DDA" "DN"  "DND" "DNN" "DNA" "DA"  "DAD" "DAN"
#[13] "DAA" "AAD" "AAN" "AAA"

這是另一個解決方案,可能不像其他解決方案那么簡潔。

它以 function 開頭,用數字123替換三個字母DNA

將此 function 應用於無序列表向量並對其應用order ,返回一個有序向量,無序列表可以用它進行切片。

library(tidyverse)

x <- c(
    "DD", "AAN", "DDD", "DNA", "DAA", "DAD", "DDN", "DDA", "DND",
    "DAN", "DNN", "DA", "AAA", "AAD", "DN", "D"
) # Unordered

er <- function(s) {
    s1 <- stringr::str_replace_all(s, "D", "1")
    s1 <- stringr::str_replace_all(s1, "N", "2")
    s1 <- stringr::str_replace_all(s1, "A", "3")
    return(s1)
}

l1 <- order(er(x))

x[l1]
#>  [1] "D"   "DD"  "DDD" "DDN" "DDA" "DN"  "DND" "DNN" "DNA" "DA"  "DAD" "DAN"
#> [13] "DAA" "AAD" "AAN" "AAA"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM