什么是将元素移动到像这样的数组中的新索引的有效方法?
A = collect(1:9) # [1,2,3,4,5,6,7,8,9]
# now lets move elements 1:3 to index 2
move!(A,1:3,2) # [4,1,2,3,5,6,7,8,9]
# lets move the 9 to index 3 now
move!(A,9:9,3) # [4,1,9,2,3,5,6,7,8]
# or this
move!(A,3:6,5) # [4,1,6,7,9,2,3,5,8]
我总是最终调整数组大小或者像疯了一样交换。是否有一种有效(=快速)的方法来解决这个问题?
答案 0 :(得分:4)
将阵列中的一系列元素移动到新位置可视为旋转较大的范围,其中包括一条边上的移动元素和目标位置。旋转足以将移动的元素移动到位并推开其他元素。
由于向量的长度保持不变,因此最好在没有分配的情况下就地执行此操作。适当地进行这种旋转有点棘手,但是可以实现,如下面的代码所示:
function rotate!(v,n::Int)
l = length(v)
l>1 || return v
n = n % l
n = n < 0 ? n+l : n
n==0 && return v
for i=1:gcd(n,l)
tmp = v[i]
dst = i
src = dst+n
while src != i
v[dst] = v[src]
dst = src
src += n
if src > l
src -= l
end
end
v[dst] = tmp
end
return v
end
move!(A,rng,loc) = begin
rotate!(view(A,min(first(rng),loc):max(last(rng),length(rng)+loc-1)),first(rng)-loc)
return A
end
A = collect(1:9)
@show move!(A,1:3,2) == [4,1,2,3,5,6,7,8,9]
@show move!(A,9:9,3) == [4,1,9,2,3,5,6,7,8]
@show move!(A,3:6,5) == [4,1,6,7,9,2,3,5,8]
最后一行代码复制了问题中的示例。基本上,只有view
分配内存,rotate!
函数完全就位。
答案 1 :(得分:1)
对于单个值,你可以做这样的事情吗?
function flipvals!(A, ind1, ind2)
flip = view.(A, [ind1,ind2])
flip .= reverse(flip)
return nothing
end
否则permute!
作为@DNF建议是个好主意。
更新:OP的评论表明,通过以下方式可以更轻松地实现这一目标:
A[ind1], A[ind2] = A[ind2], A[ind1]