将列表元素固定到Scala中的合并列表中

时间:2014-09-17 04:42:05

标签: scala collections

这似乎是一个简单的场景,但我很难理解如何优雅/功能性地解决它。我有两个列表val pinnedStrings: Seq[(String, Int)]val fillerString: Seq[Int]。我想合并它们,但每个固定的字符串保证在输出列表中的配对位置。如果我有:

val pinnedStrings = Seq("apple" -> 1, "banana" -> 4, "cherry" -> 6)
val fillerStrings = Seq("alpha", "bravo", "charlie", "delta", "echo", "foxtrot") 

然后输出应为:

Seq("alpha", "apple", "bravo", "charlie", "banana", "delta", "cherry", "echo", "foxtrot")

让我们说如果没有足够的填充物到达固定字符串,我们会丢弃固定字符串。 (或者,如果将所有剩余的固定弦放在最后也更简单,那也很好。)

3 个答案:

答案 0 :(得分:3)

或者:

scala> val pinnedStrings = Seq("apple" -> 1, "banana" -> 4, "cherry" -> 6) 
pinnedStrings: Seq[(String, Int)] = List((apple,1), (banana,4), (cherry,6))

scala> val fillerStrings = Seq("alpha", "bravo", "charlie", "delta", "echo", "foxtrot")
fillerStrings: Seq[String] = List(alpha, bravo, charlie, delta, echo, foxtrot)

scala> (fillerStrings /: pinnedStrings) { case (acc, (s, i)) => ((acc take i) :+ s) ++ (acc drop i) }
res0: Seq[String] = List(alpha, apple, bravo, charlie, banana, delta, cherry, echo, foxtrot)

答案 1 :(得分:1)

我在写了这个问题之后解决了这个问题,但是因为我已经付出了努力,所以我想分享这个问题:

val pinnedStrings = Seq("apple" -> 1, "banana" -> 4, "cherry" -> 6) 
val fillerStrings = Seq("alpha", "bravo", "charlie", "delta", "echo", "foxtrot") 

// Preadjust the specified indices to account for earlier pinned strings 
val pinnedStringsAdjusted = pinnedStrings.sortBy(_._2).zipWithIndex.map { case ((item, position), index) => (item, position - index) }

// Take advantage of the stability of `sortBy` to give pinned strings priority 
(pinnedStrings ++ fillerStrings.zipWithIndex).sortBy(_._2).map(_._1)

// Output
// res5: Seq[String] = List(alpha, apple, bravo, charlie, banana, delta, cherry, echo, foxtrot)

如果两个固定字符串具有匹配的索引,则应该按预期工作用于相邻的固定索引,但会产生奇怪的行为。如果其他人也有想法,请打开其他选项。

答案 2 :(得分:1)

有时,如果用现有的集合组合器来实现某些东西感觉很麻烦,那么建议尝试直接递归实现。

这是一种方式:

def fill[A](pinned: List[(A, Int)], filler: List[A]): List[A] = {
  def loop(pinned: List[(A, Int)], filler: List[A], i: Int, result: List[A]): List[A] = {
    (pinned, filler) match {
      case ((a, `i`) :: tail, _) => loop(tail.dropWhile(_._2 == i), filler, i + 1, a :: result)
      case (_, (a :: tail))      => loop(pinned, tail, i + 1, a :: result)
      case _                     => result // no filler left
    }
  }
  loop(pinned.sortBy(_._2), filler, 0, Nil).reverse
}

val pinnedStrings = List("apple" -> 1, "apple2" -> 1, "banana" -> 4, "cherry" -> 6)
val fillerStrings = List("alpha", "bravo", "charlie", "delta", "echo", "foxtrot") 

fill(pinnedStrings, fillerStrings) // List(alpha, apple, bravo, charlie, banana, delta, cherry, echo, foxtrot)

请注意,它不需要对集合进行多次传递。