2016-03-07 51 views

回答

8

另一个类似的方法是:

l match{ 
    case Nil   => Nil 
    case xs :+ y => xs :+ change(y) 
} 
2

你可以做这样的事情:

val l2 = l1.dropRight(1) :+ change(l1.last) 

话虽如此,请记住,列表是访问其头部(并在尾部进行操作)的良好数据结构,但对于随机和直接访问而言效率非常低。如果您需要访问最后一个元素,那么使用直接访问结构(如数组或向量)会更有效率。

+1

此迭代通过同一个列表两次。 – Rumoku

+1

这实际上是3次,因为插入到最后的位置。我已经强调,使用列表并不是最理想的。 – hasumedic

-1

必须承认,List这个代码效率相当低。 splitAt函数具有复杂性O(n) ...但同样的复杂性具有.last函数。假设获得更好的性能,你应该使用一些索引集合而不是列表。

l.splitAt(l.size - 1) match { 
    case (l1, l2) => l1 ::: l2.map(modify(_)) 
    } 
1

也许你正在寻找的东西,如: list.init :+ changes(list.last) 但是例如由@mfirry提供的运行速度更快和安全。 对于良好的性能,您可以使用矢量而不是列表

0

版本(根据链接问题中接受的答案进行调整)只能遍历列表两次。并且很明显:)

val l2 = (l1.reverse match{ 
    case Nil => Nil 
    case x::xs => change(x)::xs 
}).reverse 

如果您有一个不可变的列表,那么不可能比迭代两次做得更好。一旦找到在端部元件,第二个与被改变的一个

0

稍微更通用的版本来替换它(仍然接受只列出了其输入)

def mutateLast[A, R](l: List[A])(f: A => A)(implicit cb: CanBuildFrom[List[A], A, R]): R = { 
    val builder = cb(l) 

    @annotation.tailrec 
    def loop(l: List[A]): R = l match { 
     case Nil => builder.result() 
     case h :: Nil => 
     builder += f(h) 
     builder.result() 
     case h :: t => 
     builder += h 
     loop(t) 
    } 

    loop(l) 
    } 

    val l = List(1, 2, 3) 
    val mutated = mutateLast(l)(x => x * 2) 
    println(mutated) 

}

相关问题