[英]Sorting strings lexicographically based upon certain character order
我正在努力解决 Rosalind 问题,并且陷入了Ordering Strings of Varying Length Lexicographically问题。
到目前为止,我已经成功地创建了不同长度字母的所有正确排列。 现在的主要问题是如何根据字母提供的顺序对它们进行排序。
示例输入是字母DNA
。 但在 n <= 4 个排列中最多可以有 12 个唯一字母。
对于示例 n = 3。这会产生 39 种不同的重复排列,但这些排列随后将按照D
在N
在A
之前的顺序按字典顺序排序。
这意味着正确的顺序是:
正确的 | 不正确 |
---|---|
丁 | 一种 |
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
脚步:
strsplit(.., "")
将字符串拆分为单个字母。match(.., table=ltrs)
用ltrs
中的索引替换一个字母,这给了我们正确的字母优先级/排序。`length<-`
是因为我们随后将对它们进行rbind
,但这只有在它们都具有相同的长度时才有效。 执行此步骤(与max(lengths(..))
一起使用NA
填充较短的向量,以便所有子向量具有相同数量的元素。do.call(Map, c(f=c, inds))
将长度为n
的m
个向量列表转置为长度为n
的列表,每个列表都有m
个元素。 这对下一步非常有帮助......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 开头,用数字1
、 2
和3
替换三个字母D
、 N
和A
。
将此 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.