2

What is the proper way to add many items to a list? I assume just using many add-to-lists is not the normal way?

  • 1
    The question is not very clear. In what form are you given the items to begin with? Are they already in some (other) list? or vector? What do you mean by "proper" - what are you expecting/preferring? What are your concerns about the different ways of adding items to a list? Do you care whether the list is the value of a global variable, and you want to be sure the variable's value is updated? Do other lists share list structure with the list? – Drew Jan 10 '18 at 15:27
3

There are many different ways. Not sure if there's a particularly "proper" way. There are considerations you should take depending on how you want to add it (destructively, non-destructively) or if you care a lot about efficiency.

original list (1) things you want to add (2 3 4)

There are many different ways of adding. Things can be added destructively, meaning the original set of numbers is modified or non-destructively, just generating a new list. To see more look at list modification.

This is non-destructive. (append '(1) '(2 3 4)) ;=> '(1 2 3 4)

This is destructive and more indirect (more of a replacement than addition), here it replaces the last element of the list 2 with 2 3 4. Which has the net effect of adding to the list.

If your list is in a variable: (setq my-list '(1 2))

(setcdr my-list '(2 3 4)) ;=> '(2 3 4)

my-list ;=> '(1 2 3 4).

You could also just do a loop with add-to-list or cons. Note I'm assuming you don't care about order.

(dolist (thing things) (add-to-list 'list-var thing))

(dolist (thing things) (cons thing list-var))

I usually use the append as it is short to write and more direct. It also is probably among the fastest because it is written in C code whereas add-to-list is in elisp.

  • append is only efficient if all additional elements are already contained in a list and that list is added. It is inefficient for adding many elements sequentially or in small hunks at the tail since in this case its cost grows quadratically with the number of list entries. Note that I have confirmed that fact by timing. – Tobias Jan 10 '18 at 16:54
2

The proper way to add many items to a list is consing in a loop.

If l is the list variable you add an item i by

(setq l (cons i l))

for which you can use the shorthand

(push i l)

The computational cost of this operation is independent of the length of the list l.

After collecting the items in this way they are in reverse order. If it is important to retain the order you can call

(setq l (nreverse l))

as the last action or just return (nreverse l). The cost of nreverse grows just linearly with the length of the list.

The costs of adding all elements with add-to-list grow quadratically with the length of the list (even without append set to t).

If you want to add an item to a list only if it is not already present. You have to search for that item. In that case you could consider using a hashmap (search the elisp info files for make-hash-table) or a sorted list to reduce the computational costs. Note that a single hash access is costly but the read/write access time is essentially independent on the number of elements in the hash.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.