滚动列表的最简单方法是什么?
考虑以下列表:
myList : [0,1,4,6,3]
我正在寻找一个roll()
函数:
(%i0) roll(myList,1)
(%o0) [3,0,1,4,6]
(%i1) roll(myList,-1)
(%o1) [1,4,6,3,0]
我可以通过调用:
来获得相同的结果myItem : pop(myList)
myList : append(myList,myItem)
问题是这只能在一个方向上工作(我知道没有pop_back()
函数(?))并且它是一个双线性的。有没有更好的方法呢?
答案 0 :(得分:2)
嗯,没有内置功能。但我认为你可以使用rest
来获得你想要的效果。
(%i10) rotate (e, n) :=
if atom(e) then e
else block ([a : args(e)],
apply (op(e),
append (rest (a, length(a) - n), rest (a, -n)))) $
(%i11) foo : [a, b, c, d, e, f, g];
(%o11) [a, b, c, d, e, f, g]
(%i12) rotate (foo, 2);
(%o12) [f, g, a, b, c, d, e]
(%i13) rotate (foo, 7);
(%o13) [a, b, c, d, e, f, g]
这适用于所有表达式,而不仅仅是列表。
(%i16) rotate (f(1,2,3), 2);
(%o16) f(2, 3, 1)
此实现不会使参数数量大于n
或n
,但我认为处理它会很容易。
我假设rotate
将较小指数的元素移动到更大的指数。同样,如果您希望默认值朝另一个方向发展,我认为这样做很容易。
编辑:实际上没有必要将op(e)
和args(e)
分开。当rest(e, ...)
不是列表时,您可以致电e
,它会做正确的事情。所以更简洁的版本是:
rotate (e, n) :=
if atom(e) then e
else append (rest (e, length(e) - n), rest (e, -n)) $