有效地组合两个列表产生一组新列表

时间:2021-06-29 10:30:44

标签: 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))

这有效,但显然效率低下,因为列表的每一步都涉及 consing、合并和 flatMapping。此外,我试图解决的问题涉及更大的列表,有时每个列表有多个对不同或相同集合的引用。

有没有更有效的方法?

1 个答案:

答案 0 :(得分:2)

呃,是的 .. 变得昂贵(但仍然是多项式 - 我认为,它是 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))