这是我确实解决的问题,但是作为一个完全命令式的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))
答案 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) }
}