我有一个不可变的列表,我需要在其中交换位置。有没有简单的方法呢?
以下是我的代码:
def swap(i:Int, j:Int,li:List[T]):List[T]={
if(i>=li.size && j >=li.size)
throw new Error("invalie argument");
val f = li(i)
li(i) = li(j) //wont work
li(j) = f;//wont work
li;
}
最初,我尝试将其转换为数组,更改位置,然后再将其转换为List。有什么简单的方法吗?
答案 0 :(得分:13)
这样做很容易(但不是很有效)
val l = List(1,2,3)
l: List[Int] = List(1, 2, 3)
l.updated(0,l(2)).updated(2,l(0))
res1: List[Int] = List(3, 2, 1)
答案 1 :(得分:5)
您只能在O(n)
中创建新列表。您可能想要使用不同的数据结构。你可以这样做:
def swap[T](i:Int, j:Int,li:List[T]):List[T]={
if(i>=li.size || j >=li.size || i >= j)
throw new Error("invalid argument")
li.dropRight(li.length - i) ::: (li(j) :: li.dropRight(li.length - j).drop(i+1)) ::: ((li(i) :: li.drop(j + 1)))
}
它不是很优雅,但它会完成这项工作。基本上,我正在对索引i
&上的列表进行切片。 j
,所以我有5个部分:i
之前的列表前缀,i
,i
之间的部分。 j
独占,j
以及j
之后列表的后缀。从那里,它与i
&的简单连接j
转过身来。如果你使用列表缓冲区可以更有效,如果你将使用可变Array
s更高效...
答案 2 :(得分:0)
我不确定这是否是这样做的好方法但是我怎么样这样呢?
def swapElements(list: List[Any], first: Int, second: Int) = {
def elementForIndex(index: Int, element: Any) = {
if(index == first) {
list(second)
} else if(index == second){
list(first)
} else {
element
}
}
for(element <- ((0 to list.size - 1) zip list).to[List])
yield elementForIndex(element._1, element._2)
}
答案 3 :(得分:0)
您可能想要尝试的一件事(取决于应用程序,例如您经常更新点等等)是使用&#39; Zipper&#39;,见下文。你可能想要添加一个&#39; moveTo&#39;方法或类似方法。如果处理不可变列表,您可能会有更少的更新。我认为上面的简单解决方案可能最适合小型列表。
编辑:如果你知道你正在追逐彼此附近的元素等,可能会被调整。
case class Zipper[A](focus: A, left: List[A], right: List[A]) {
def fromZipper: List[A] = left ::: List(focus) ::: right
/** Will throw NoSuchElementException if try to move beyond start. */
/** directions are forward and backward across the list. */
def moveForward: Zipper[A] = Zipper(right.head,left :+ focus,right.tail)
def moveBackward: Zipper[A] = Zipper(left.last,left.init,focus :: right)
/** Update the focus element. */
def update(a: A): Zipper[A] = Zipper(a,left,right)
}
def apply[A](left: List[A], focus: A, right: List[A]): Zipper[A]
= Zipper(focus,left,right)
def apply[A](xs: List[A]): Zipper[A]
= Zipper(xs.head,List.empty[A],xs.tail)