排序变量,排序

时间:2014-08-04 14:27:41

标签: java r graph

如何在给定条件下订购一组变量。

如果给我:

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

鉴于任何数量的变量,我如何根据这些条件将它们从最小到最高排名?如果情况不可能,请在代码中加入中断。谢谢。

2 个答案:

答案 0 :(得分:1)

这适用于您的示例( - 但未检查边缘情况),它使用dag&#39; s(有向非循环图)具有自然顺序的想法。您的示例就是这种情况。语句中的一个不可能的场景会导致图中出现一个循环,因此我们可以使用它来抛出错误。

如果您的所有陈述都是严格的

,则此方法有效
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方式) - 通过描述具有双向边的相等顶点。如果完全指定了模型/语句(它应该是),我们有一个完整的图形,我们可以使用这样的事实:如果两个顶点相等,它们应该具有比它们更大的相同顶点集,并且相同的顶点比它们小 - 否则抛出错误。

因此,我们使用parentschildren的概念,并在等效顶点(A&lt; B&lt; =&gt;父&lt; 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"))

我没有检查过所有边缘情况或更大的图表,但它应该给你一个想法让你开始(如果你想这样做)

答案 1 :(得分:1)

这是另一种为元素定义自定义顺序运算符然后调用内置方法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"

此策略由this answer建议,但我在这里使用的方法更简单。