如何替换Scala中列表中的第一个匹配项?
问题描述:
比方说,你有:如何替换Scala中列表中的第一个匹配项?
List(('a', 1), ('b', 1), ('c', 1), ('b', 1))
,你要替换的第一('b', 1)
与('b', 2)
,你不希望它(一)浪费时间来评估过去的第一场比赛和(b)更新任何进一步匹配的元组。
在Scala中这样做有一个相对简洁的方法(即,不需要将列表拆分并重新连接)。像一个假想的功能mapFirst
与递增的第一个匹配的值返回列表:
testList.mapFirst { case ('b', num) => ('b', num + 1) }
答
你不必把整个名单除了我猜。 (只有等到元素被发现)
def replaceFirst[A](a : List[A], repl : A, replwith : A) : List[A] = a match {
case Nil => Nil
case head :: tail => if(head == repl) replwith :: tail else head :: replaceFirst(tail, repl, replwith)
}
呼叫例如:
replaceFirst(List(('a', 1), ('b', 1), ('c', 1), ('b', 1)), ('b', 1), ('b', 2))
结果:
List((a,1), (b,2), (c,1), (b,1))
与部分功能和implicits(这看起来更像是一种你mapFirst):
implicit class MyRichList[A](val list: List[A]) {
def mapFirst(func: PartialFunction[A, A]) = {
def mapFirst2[A](a: List[A], func: PartialFunction[A, A]): List[A] = a match {
case Nil => Nil
case head :: tail => if (func.isDefinedAt(head)) func.apply(head) :: tail else head :: mapFirst2(tail, func)
}
mapFirst2(list, func)
}
}
并像这样使用它:
List(('a', 1), ('b', 1), ('c', 1), ('b', 1)).mapFirst {case ('b', num) => ('b', num + 1)}
答
你可以相对容易地模拟这样的功能。最快的(实现的角度来看,不一定是性能明智)我能想到的是这样的:
def replaceFirst[A](a:List[A], condition: (A)=>Boolean, transform:(A)=>(A)) = {
val cutoff =a.indexWhere(condition)
val (h,t) = a.splitAt(cutoff)
h ++ (transform(t.head) :: t.tail)
}
scala> replaceFirst(List(1,2,3,4,5),{x:Int => x%2==0}, { x:Int=> x*2 })
res4: List[Int] = List(1, 4, 3, 4, 5)
scala> replaceFirst(List(('a',1),('b',2),('c',3),('b',4)), {m:(Char,Int) => m._1=='b'},{m:(Char,Int) => (m._1,m._2*2)})
res6: List[(Char, Int)] = List((a,1), (b,4), (c,3), (b,4))
答
使用span
只找到第一个元素。即使case
未满足,也不应抛出异常。无需多言,您可以指定尽可能多的个案。
implicit class MyRichieList[A](val l: List[A]) {
def mapFirst(pf : PartialFunction[A, A]) =
l.span(!pf.isDefinedAt(_)) match {
case (x, Nil) => x
case (x, y :: ys) => (x :+ pf(y)) ++ ys
}
}
val testList = List(('a', 1), ('b', 1), ('c', 1), ('b', 1))
testList.mapFirst {
case ('b', n) => ('b', n + 1)
case ('a', 9) => ('z', 9)
}
// result --> List((a,1), (b,2), (c,1), (b,1))
恐怕这个解决方案浪费了堆栈。在大列表中,解决方案将抛出'*Exception'。最好将解决方案更改为'@ tailrec'。通常这是通过函数内部的'ListBuffer [T]'参数完成的。 –