Как заказать набор переменных с заданными условиями.
Если мне дадут:
A < B, B < C, and C < A. This is impossible.
A < B, C < B, and A < C. The order, from least to greatest, is A, C, B.
Я предпочитаю R, если я могу просто передать строки метода, такие как c("A<B", "C<B", "A<C")
а оттуда метод возвращает c("A","C", "B")
Учитывая любое количество переменных, как я могу ранжировать их от наименьшего до наибольшего, исходя из этих условий? Пожалуйста, включите разрыв кода, если сценарий невозможен. Спасибо.
Здесь другой метод, который определяет пользовательские операторы порядка для ваших элементов, а затем вызывает встроенный метод sort
.
rules <- c("A<B", "C<B", "A<C")
vec <- c("A", "B", "C", "A")
class(vec) <- 'letters'
'[.letters' <- function(x, i) {
x <- unclass(x)
e <- x[i]
class(e) <- 'letters'
e
}
'==.letters' <- function(x, y) unclass(x) == unclass(y)
'>.letters' <- function(x, y) paste(y, x, sep='<') %in% rules
sort(vec)
# [1] "A" "A" "C" "B"
Эта стратегия была предложена этим ответом, но метод, который я здесь использую, проще.
Это работает для вашего примера (но не проверяется для случая кромки). В нем используется идея, что dag (направленные ациклические графики) имеют естественный порядок. Это относится к вашему примеру. Невозможный сценарий в операторах приведет к циклу в графе, поэтому мы можем использовать его для выброса ошибки.
Это работает, если все ваши заявления строги
library(igraph)
f <- function(X) {
d <- do.call("rbind", strsplit(X , "<"))
g <- graph.data.frame(d)
if(is.dag(g))
V(g)$name[topological.sort(g)]
else
stop("Graph has cycles")
}
f(c("A<B", "C<B", "A<C"))
f(c("C<B", "A<C", "A<B"))
f(c("A<B", "B<C", "C<A"))
О коде:
# this splits the string into two columns
# interpreted as from -> to by graph
do.call("rbind", strsplit(X , "<"))
# generate graph from edges (d)
g <- graph.data.frame(d)
is.dag(g) # checks if the graph is acyclic
# if there are no cycles return the vertice names in topological order
V(g)$name[topological.sort(g)]
РЕДАКТИРОВАТЬ
Чтобы включить случай, когда вершины эквивалентны, ограничение использования приведенного выше. Но мы все еще можем использовать графический метод (хотя он менее естественный, а не способ R) - описывая равные вершины с двунаправленными ребрами. Если модель/операторы полностью определены (что должно быть), у нас есть полный граф, и мы можем использовать тот факт, что если две вершины равны, они должны иметь тот же набор вершин, которые больше их и те же, в противном случае выведите ошибку.
Поэтому мы используем идеи parents
и children
и сравниваем их между эквивалентными вершинами (A <B <=> parent <child).
Первая часть функции предназначена для случаев, когда утверждения все строго меньше или больше. Во второй части сравниваются родительские и дочерние узлы, имеющие оператор эквивалентности.
f <- function(X) {
l <- do.call("rbind", strsplit(X[grepl("<", X)] , "<"))
if(!any(grepl("==", X))) {
g <- graph.data.frame(l)
if(is.dag(g))
V(g)$name[topological.sort(g)]
else
stop("Impossible")
}
else {
e <- do.call("rbind", strsplit(X[grepl("==", X)] , "=="))
g <- graph.data.frame(rbind(l, e, e[,2:1]))
par <- function(g)
setNames(lapply(neighborhood(g, 1, mode="in"),
function(i) sort(V(g)$name[i])), V(g)$name)
ch <- function(g)
setNames(lapply(neighborhood(g, 1, mode="out"),
function(i) sort(V(g)$name[i])), V(g)$name)
pareq <- apply(e, 1,
function(i)
identical(par(g)[[i[1]]], par(g)[[i[2]]]))
cheq <- apply(e, 1,
function(i)
identical(ch(g)[[i[1]]], ch(g)[[i[2]]]))
if(all(pareq & cheq)) {
g <- graph.data.frame(rbind(l,e))
V(g)$name[topological.sort(g)]
}
else
stop("Impossible")
}
}
Несколько примеров
f(X = c("C<B", "A<C", "A<B"))
f(X = c("C==B", "C==A", "A<B"))
f(X = c("C==B", "C<A", "A<B"))
f(X = c("B==C", "C<A", "B<A"))
Я не проверял это для всех случаев краев или больших графиков, но он должен дать представление о том, чтобы вы начали (если вы хотите идти этим путем)