将缺失值插入列表

时间:2016-05-07 16:43:22

标签: scala

假设我们有一个与某个值相关联的范围列表,比如List[(Int, Int, Foo)]。保证范围是不相交的,因此永远不会重叠。范围不包括给定字符串的整个范围。我想将每个Foo与字符串的某些部分相关联,以便将字符串拆分为(String, Option[Foo])的部分。

我的想法是将此List[(Int, Int, Foo)]转换为List[(Int, Int, Option[Foo])],以便填写每个缺失的范围并与无关联。然后可以映射此新列表以将每个Foo与字符串的某些部分相关联。

一些具体的代码

case class Foo(i: Int)
val str = "a" * 99 // A random string of length 99
val input = List((5, 10, Foo(1)), (56, 60, Foo(2))
// ???
val filledInValues = List(
  (0, 4, None),
  (5, 10, Some(Foo(1))),
  (11, 55, None),
  (56, 60, Some(Foo(2))),
  (61, 98, None)
)
val res = filledInValues map { case (start, end, f) =>
  (str.substring(start, end), f)
}

我应该如何从inputfilledInValues,或从inputres

2 个答案:

答案 0 :(得分:6)

这个很有趣。

case class Foo(x:Int)

val xs = List((5, 10, Foo(1)), (56, 60, Foo(2)))
val str = "a" * 99 // A random string of length 99

// change the Foo to Option[Foo]. We do this now so we can use None
// in the sentinels we're about to add.

val ys = xs.map{case(a,b,c) => (a, b, Option(c))}

// Add dummy/sentinel elements to start and end
val zs = (-1, -1, None:Option[Foo])::(ys:+ ((str.length, str.length, None:Option[Foo])))

// Now take each pair and if there's a gap, use the first, then  a (n, m, None) element
// if no gap, just the first of the pair
zs.sliding(2).flatMap{
  case List(a,b) => 
    if (a._2+1 != b._1)
         List(a, (a._2 + 1, b._1 -1, None:Option[Foo]))
    else
         List(a)
  }.toList.tail
// and drop the dummy element from the beginning
// Note because we never return the second of the pair, the end sentinel 
// value gets discarded automatically

 //> res0:= List((0,4,None),
                 (5,10,Some(Foo(1))),
                 (11,55,None),
                 (56,60,Some(Foo(2))),
                 (61,98,None))

答案 1 :(得分:0)

def ranges(str: String, ls: List[(Int, Int, Foo)]): List[(Int, Int, Option[Foo])] = {
  val length = str.length
  def loop(i: Int, ls: List[(Int, Int, Foo)], acc: List[(Int, Int, Option[Foo])]): List[(Int, Int, Option[Foo])] = {
    ls match {
      case Nil if i < length => (i, length -1, None) :: acc
      case Nil => acc
      case (start, end, _) :: lss if start > i => loop(start, ls, (i, start - 1, None) :: acc)
      case (start, end, f) :: lss if start == i => loop(end + 1, lss, (start, end, Some(f)) :: acc)
      case _ => throw new IllegalStateException
    }
  }
  loop(0, ls, Nil).reverse
}

测试它:

scala> ranges(str, input)
res0: List[(Int, Int, Option[Foo])] = List((0,4,None), (5,10,Some(Foo(1))), (11,55,None), (56,60,Some(Foo(2))), (61,98,None))