#scala
Вопрос:
У меня есть два набора списков:
A: {1 -> B -> 3, 4 -> B -> 5 }
B: { 7 -> 8 }
которые я хочу объединить, что приведет к
A' : {1 -> 7 -> 8 -> 3, 4 -> 7 -> 8 -> 5 }
Примечание B
. В одном списке может быть несколько ссылок.
A: {B -> 1 -> B}
B: {2,3}
A' : {2 -> 1 -> 2, 2 -> 1 -> 3, 3 -> 1 ->2, 3 -> 1 -> 3}
Мой текущий подход является рекурсивным и работает с каждым из отдельных списков A
:
object dummy {
trait Step
// I owe you referencing another set
case class IOU(ref : String)
// a simple step within the list
case class Step(id : Long)
def recursiveResolve(
id: String,
to: Set[Seq[Step]],
on: Seq[Step]): Set[Seq[Step]] = {
on match {
// here we are done and can return the empty set to resolve the recursion tree
case Nil => Set()
// we have still work left and now work on the first element remaining
case mul :: tiple =>
val step: Set[Seq[Step]] = mul match {
// if we have an I owe you that references the replace in list
case x: IOU if x.ref == id =>
// return the replace in set of lists
to
case x => Set(Seq(x))
}
val next: Set[Seq[Step]] = recursiveResolve(id, to, tiple)
// if the next step returned non empty we have to merge
if (next.nonEmpty) {
step.flatMap { elem: Seq[Step] =>
next.map { nextElem: Seq[Step] =>
elem nextElem
}
}
} else {
step
}
}
}
}
val A : Set[Seq[Step]] = Set( Seq( Step(1), IOU("B"), Step(3)), Seq( Step(4), IOU("B"), Step(5) ))
val B : Set[Seq[Step]] = Set( Seq(Step(7), Step(8) ) )
val result : Set[Seq[Step]] = A.flatMap(elem => recursiveResolve("B",B,elem))
Это работает, но, очевидно, ужасно неэффективно, поскольку каждый шаг списка включает в себя сохранение, объединение и сопоставление. Кроме того, проблема, которую я пытаюсь решить, включает в себя большие списки, иногда с несколькими ссылками на каждый список на разные или один и тот же набор.
Существует ли более эффективный подход?
Ответ №1:
Ух, да .. это становится дорогим (но все равно полиномиальным — я думаю, это так O(A*N*B^2)
)
def resolve(bs: Set[Seq[Step]])(s: Seq[Step]): Set[Seq[Step]] = s match {
case Seq(IOU(_), tail@_*) => bs.flatMap { b => resolve(bs)(tail).map(b : _) }
case Seq(head, tail@_*) => resolve(bs)(tail).map(head : _)
case Seq() => Set(Seq())
}
A.flatMap(resolve(B))
Комментарии:
1. B может быть набором списков. Чтобы пример был простым, я его не демонстрировал.
2. Верно. Как я уже сказал, я понятия не имею, что вы собираетесь делать с набором.
3. Тогда должно было бы появиться еще больше списков
A: {1 -> B -> 2} B{1,2}
A: {1 -> 1 -> 2, 1 -> 2 -> 2}
. Эта проблема имеет потенциал для неполиномиального роста, поэтому мне нужно ее оптимизировать.4. вы уверены, что
resolve
используется aflatMap
, а не amap
. Я получаю ошибку типа.5. Я думаю, что я нашел проблему с вашим решением
A: { B -> 1 -> B } B: {2, 3}
, которая должна привести кA': {2 -> 1 -> 2, 2 -> 1 -> 3, 3 -> 1 -> 2, 3 -> 1 -> 3}
, но приводит толькоA':{2 -> 1 -> 2, 3 -> 1 -> 3}
к вашему решению.