Skip to content

Commit 6f03816

Browse files
committed
Add: Collecting items into a list
1 parent 9b398d5 commit 6f03816

File tree

2 files changed

+120
-3
lines changed

2 files changed

+120
-3
lines changed

README.org

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,64 @@ users, as it provides familiar and intuitive interfaces with usual keys (for mov
266266

267267
*** Best practices :best_practices:
268268

269+
**** Collecting items into a list :lists:
270+
271+
Here are some examples of fast ways to collect items into a list.
272+
273+
#+CAPTION: Benchmarking code that collects items into a list.
274+
#+BEGIN_SRC elisp
275+
(bench-multi-lexical :times 500000 :ensure-equal t
276+
:forms (("cl-loop" (let ((l '(1 2 3 4)))
277+
(cl-loop for val in l
278+
collect val)))
279+
("push-nreverse with setf/pop" (let ((l '(1 2 3 4))
280+
val r)
281+
(while (setf val (pop l))
282+
(push val r))
283+
(nreverse r)))
284+
("push-nreverse with when-let*/pop" (let ((l '(1 2 3 4))
285+
r)
286+
(while (when-let* ((val (pop l)))
287+
(push val r)))
288+
(nreverse r)))
289+
("nconc with when-let*/pop" (let ((l '(1 2 3 4))
290+
r)
291+
(while (when-let* ((val (pop l)))
292+
(setf r (nconc r (list val)))))
293+
r))
294+
("nconc with setf/pop" (let ((l '(1 2 3 4))
295+
val r)
296+
(while (setf val (pop l))
297+
(setf r (nconc r (list val))))
298+
r))))
299+
#+END_SRC
300+
301+
#+RESULTS:
302+
| Form | x faster than next | Total runtime | # of GCs | Total GC runtime |
303+
|----------------------------------+--------------------+---------------+----------+------------------|
304+
| cl-loop | 1.01 | 0.154578 | 0 | 0 |
305+
| push-nreverse with setf/pop | 1.02 | 0.155930 | 0 | 0 |
306+
| push-nreverse with when-let*/pop | 1.23 | 0.159211 | 0 | 0 |
307+
| nconc with setf/pop | 1.06 | 0.195685 | 0 | 0 |
308+
| nconc with when-let*/pop | slowest | 0.207103 | 0 | 0 |
309+
310+
As is usually the case, the =cl-loop= macro expands to the most efficient code, which uses =(setq val (car ...=, =push=, and =nreverse=:
311+
312+
#+CAPTION: Expansion of =cl-loop= form in the benchmark.
313+
#+BEGIN_SRC elisp
314+
(cl-block nil
315+
(let* ((--cl-var-- l)
316+
(val nil)
317+
(--cl-var-- nil))
318+
(while (consp --cl-var--)
319+
(setq val (car --cl-var--))
320+
(push val --cl-var--)
321+
(setq --cl-var-- (cdr --cl-var--)))
322+
(nreverse --cl-var--)))
323+
#+END_SRC
324+
325+
However, in some cases =cl-loop= may expand to code which uses =nconc=, which, as the benchmark shows, is much slower. In that case, you may write the loop without =cl-loop= to avoid using =nconc=.
326+
269327
**** Filtering a list
270328

271329
Using ~-select~ from =dash.el= seems to be the fastest way:

index.html

Lines changed: 62 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)