2013-10-29 86 views
1

比方说,你有:如何替换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) }

回答

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)) 

与部分功能和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)} 
+1

恐怕这个解决方案浪费了堆栈。在大列表中,解决方案将抛出'StackOverflowException'。最好将解决方案更改为'@ tailrec'。通常这是通过函数内部的'ListBuffer [T]'参数完成的。 –

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)) 
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)) 
相关问题