我们说你有:
List(('a', 1), ('b', 1), ('c', 1), ('b', 1))
并且您希望将第一个('b', 1)
替换为('b', 2)
,并且您不希望它(a)浪费时间评估第一场比赛并且(b)更新任何进一步的匹配元组。
在Scala中是否有相对简洁的方法(即,不将列表拆分并重新连接)。像假想函数mapFirst
那样返回列表,第一个匹配值递增:
testList.mapFirst { case ('b', num) => ('b', num + 1) }
答案 0 :(得分:2)
我猜你不必将整个列表分开。 (只有在找到元素之前)
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))
具有部分功能和隐含的方式(看起来更像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)}
答案 1 :(得分:2)
您可以相对轻松地模拟此类功能。我能想到的最快(实现方式,不一定是性能方面)是这样的:
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))
答案 2 :(得分:1)
使用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))