在Emacs Lisp中逐步迭代列表

在Emacs Lisp中逐步迭代列表,emacs,elisp,slice,Emacs,Elisp,Slice,我在Elisp中有一个列表。如何返回一个由从第一个元素开始的第n个元素组成的列表?在Python中,我使用了切片表示法: >>> range(10)[::3] [0, 3, 6, 9] 我在list API中找不到任何有用的东西,因此我使用以下方法编写了解决方案: 顺便说一下,(lambda(xs)(nthcdr n xs))可以用dash.el的部分应用程序函数重写:(-partial'nthcdr n) 循环宏似乎有些过分。如何在Emacs Lisp中一步一步返回元素?下

我在Elisp中有一个列表。如何返回一个由从第一个元素开始的第n个元素组成的列表?在Python中,我使用了切片表示法:

>>> range(10)[::3]
[0, 3, 6, 9]
我在list API中找不到任何有用的东西,因此我使用以下方法编写了解决方案:

顺便说一下,
(lambda(xs)(nthcdr n xs))
可以用
dash.el
的部分应用程序函数重写:
(-partial'nthcdr n)


循环
宏似乎有些过分。如何在Emacs Lisp中一步一步返回元素?

下面是一个简短的示例,在循环中使用
-partial
和普通lambda进行比较:

(需要“cl-lib”)
(1)无
(setq bigdata(数字序列1 10000)))
(每n-n-1取一次)
(x中x的cl循环由(lambda(xs)(nthcdr n xs))
收集(x)
(每n-n-2(n xs)取一次
(x中x的cl循环由(-partial'nthcdr n)
收集(x)
(defmacro util timeit(expr)
(let((t-beg(浮动时间))
(res(dotimes)(i 1000)
(eval expr)))
(t端(浮动时间)))
(/
(-t端t-beg)
1000)))
(setq时间1
(util timeit)
(长度(每N-13个大数据)))
(setq时间2
(util timeit)
(每N-N-2 3个大数据)
(消息“%s”(/time2 time1))
调用
eval buffer
会得到大约4的结果。这意味着
(lambda(xs)(nthcdr n xs))
(-partial'nthcdr n)
快4倍, 至少没有字节编译

通过字节编译,它的性能相差12.2-13.6倍 为了一个普通的羔羊

软件包支持版本2.7中的步骤。因此,Python的
范围(10)[1:7:2]
相当于:

(-slice (number-sequence 0 9) 1 7 2) ; (1 3 5)

只需使用循环的解决方案。实际上,由于Emacs不是一种函数式语言,它的
-partial
是过分的。如果你关心性能,你就必须小心使用函数方法。@abo abo无意冒犯,但这是一个愚蠢的论点
-partial
只是
部分应用
的一个别名,它反过来只创建一个
lambda
,因此无论如何
(-partial'nthcdr n)
(lambda(xs)(nthcdr n xs))
没有任何不同,只是更短而已。任何关于dash.el性能的说法都是胡说八道,除非有确凿的数字支持。@lunaryorn,没有冒犯的意思。您是否实际查看了部分应用的代码?它添加了
循环
不具备的不必要的间接级别。这就像C++中的虚拟调用:大部分时间都有它们是可以的,但是你看不到
std::vector
有它们,是吗?@lunaryorn,刚刚完成分析,
-partial
需要60%以上的时间。实际上,对于1..10000作为数据,每选择第三个元素,平均运行1000次。毫不奇怪:
-partial
(和
apply partial
)同时使用
&rest
apply
,速度相当慢。请您将与@lunaryorn讨论的内容整合到答案中。答案与两天前相同:不要在循环中使用
-partial
。事实上,当涉及到循环时,请尽量保持原始。而且你的
步骤
函数在我看来是最优的。@abo abo,我的意思是如果你能将你的评论中的参数合并到这个问题中,那就太好了,这样你就可以很容易地理解为什么使用
-partial
是次优的。
(-slice (number-sequence 0 9) 1 7 2) ; (1 3 5)