Scala在特定位置插入列表

时间:2011-01-12 23:28:54

标签: list scala functional-programming

这是我确实解决的问题,但是作为一个完全命令式的Scala noob,我觉得我发现了一些完全不优雅的东西。任何改进的想法都赞赏。

val l1 = 4 :: 1 :: 2 :: 3 :: 4 :: Nil // original list
val insert = List(88,99) // list I want to insert on certain places

// method that finds all indexes of a particular element in a particular list
def indexesOf(element:Any, inList:List[Any]) = {
        var indexes = List[Int]()
        for(i <- 0 until inList.length) {
                if(inList(i) == element) indexes = indexes :+ i
        }
        indexes
}


var indexes = indexesOf(4, l1) // get indexes where 4 appears in the original list

println(indexes)

var result = List[Any]()

// iterate through indexes and insert in front
for(i <- 0 until indexes.length) {
        var prev = if(i == 0) 0 else indexes(i-1)
        result = result ::: l1.slice(prev, indexes(i)) ::: insert
}
result = result ::: l1.drop(indexes.last) // append the last bit from original list

println(result)

我认为更优雅的解决方案可以通过这样的方式实现,但这只是纯粹的推测。

var final:List[Any] = (0 /: indexes) {(final, i) => final ::: ins ::: l1.slice(i, indexes(i))

3 个答案:

答案 0 :(得分:14)

def insert[A](xs: List[A], extra: List[A])(p: A => Boolean) = {
  xs.map(x => if (p(x)) extra ::: List(x) else List(x)).flatten
}

scala> insert(List(4,1,2,3,4),List(88,99)){_ == 4}
res3: List[Int] = List(88, 99, 4, 1, 2, 3, 88, 99, 4)

编辑:添加了解释。

我们的目标是在另一个列表中选择的元素前面插入一个列表(名为extra)(此处称为xs - 通常用于列表,就好像有一件事{{1}然后很多它们必须是复数x)。我们希望这可以在我们可能拥有的任何类型的列表上工作,因此我们使用泛型类型xs对其进行注释。

哪些元素可以插入?在编写函数时,我们不知道,所以我们为每个元素([A])提供了一个真或假的函数。

现在,对于列表p: A => Boolean中的每个元素,我们检查 - 我们应该进行插入(即x是否为真)?如果是,我们只需构建它:p(x)只是extra ::: List(x)的元素,后跟单个项extra。 (最好将其写为x - 在最后添加单个项目。)如果不是,我们只有单个项目,但我们将其设为extra :+ x而不是{{1}因为我们希望所有东西都具有相同的类型。所以现在,如果我们有像

这样的东西
List(x)

我们的条件是我们在x之前插入4 1 2 3 4 ,我们生成

5 6

这正是我们想要的,除了我们有一个列表列表。要删除内部列表并将所有内容压缩到一个列表中,我们只需调用4

答案 1 :(得分:10)

扁平化的技巧很可爱,我不会想到在这里使用map。从我的角度来看,这个问题是折叠的典型应用,因为你想通过列表并“收集”某些东西(结果列表)。由于我们不希望我们的结果列表向后,foldRight(a.k.a。:\)在这里是正确的版本:

def insert[A](xs: List[A], extra: List[A])(p: A => Boolean) = 
  xs.foldRight(List[A]())((x,xs) => if (p(x)) extra ::: (x :: xs) else x :: xs)

答案 2 :(得分:3)

这是另一种可能性,使用Seq#patch来处理实际插入。你需要foldRight以便先处理后面的索引(插入后修改插入后所有元素的索引,否则会很棘手)。

def insert[A](xs: Seq[A], ys: Seq[A])(pred: A => Boolean) = {
  val positions = xs.zipWithIndex filter(x => pred(x._1)) map(_._2)
  positions.foldRight(xs) { (pos, xs) => xs patch (pos, ys, 0) }
}