在Guava MutableValueGraph中交换节点

时间:2017-04-21 10:09:45

标签: guava kotlin

我正试图替换com.google.common.graph.MutableValueGraph中的元素。

我需要在以下数据类上更新元素状态(我知道the docs建议小心):

data class Frame(val method: String, val merged: Boolean = false)

由于图表没有提供一种方法来交换另一个节点,我自己动手:

fun MutableValueGraph<Frame, Int>.exchangeNode(old: Frame, new: Frame): Boolean {
    if (old == new) return true

    if (isDirected) {
        this.predecessors(old).forEach { 
            this.putEdgeValue(it, new, this.edgeValue(it, old)) }
        this.successors(old).forEach { 
            this.putEdgeValue(new, it, this.edgeValue(old, it)) }
    } else {
        this.adjacentNodes(old).forEach { 
            this.putEdgeValue(it, new, this.edgeValue(it, old)) }
    }
    return this.removeNode(old)
}

但是,我遇到了ConcurrentModificationException:

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1437)
at java.util.HashMap$EntryIterator.next(HashMap.java:1471)
at java.util.HashMap$EntryIterator.next(HashMap.java:1469)
at com.google.common.graph.DirectedGraphConnections$1$1.computeNext(DirectedGraphConnections.java:113)
at com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:145)
at com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:140)
at TestKt.exchangeNode(Test.kt:292)
...

听起来很公平,因为我在for循环中交换了一堆节点,可能试图触摸已经交换过的相邻节点?

我的问题是:如何替换ValueGraph中的多个节点,保持其边缘值?

1 个答案:

答案 0 :(得分:0)

一种效率较低的方法,但应该避免ConcurrentModificationException的方法是从相关节点引出子图,然后删除旧节点并添加新节点,最后使用诱导子图将边值重新添加到:

fun MutableValueGraph<Frame, Int>.exchangeNode(old: Frame, new: Frame): Boolean {
    if (old == new) return false

    val inducedSubgraph = Graphs.inducedSubgraph(this, adjacentNodes(old) + old)

    removeNode(old)
    addNode(new)

    if (isDirected) {
        for (predecessor in inducedSubgraph.predecessors(old)) {
            putEdgeValue(predecessor, new, inducedSubgraph.edgeValue(predecessor, old))
        }
        for (successor in inducedSubgraph.successors(old)) {
            putEdgeValue(new, successor, inducedSubgraph.edgeValue(old, successor))
        }
    } else {
        for (adjacentNode in inducedSubgraph.adjacentNodes(old)) {
            putEdgeValue(adjacentNode, new, inducedSubgraph.edgeValue(adjacentNode, old))
        }
    }

    return true
}