繁体   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