Copying lists and arrays

The most basic way to copy a list or an array is simply to assign a new variable with SETQ or SETF, but this may behave in unexpected ways. Let us look at an example:

Try running the above in Audacity’s Nyquist Prompt effect (use the Debug button to see the output), and you may be surprised to see that mylist has also been modified, and the final line also prints (1 2 9 4 5).

What has happened is that mylist-copyis a shallow copy of mylist. What that means is that the variable mylist-copy points to the same data object in memory as the original list. Both variables, mylist and mylist-copy are names for the same list object. If either variable is modified, it is the same list object that is modified, so we see the change in both mylist and mylist-copy.

The same thing occurs with arrays, as we can see in this example:

How to create an independent copy of a list

If we want to create an independent copy of a list, we need to create a new list object with the same contents as the list that we are copying.

Duplicating long lists

As you have no doubt noticed, the code uses a Lisp loop to copy the elements of the original list. While this is fine for short lists, it could be quite slow for long lists. Unfortunately Nyquist does not have a built-in function for creating a deep copy of a list, so we need to devise our own way of doing so.

Quick and dirty

This first method is reasonably fast because the heavy lifting is done by the REVERSE function, which is written in C. The reason that it works is because (reverse list) returns a new list. All we do is to reverse the original list, and reverse it back again (if necessary) into the correct order:

This is very much faster on long lists than our original loop method, but it is clearly an ugly hack as we never had any intention to actually reverse the list.

A better solution

In this version we will use MAPCAR (also written in C) to construct a new list. So that we can easily reuse the code when required, we will write our new version as a function that we can call whenever we need a deep copy.

MAPCAR applies a function (in this case a lambda expression) to each element of a list, and returns the new list. The LAMBDA expression here simply returns the value passed to it, so the new list is a copy of the original list.

Testing our new list copy function with our original code:

Writing a suitable function for arrays is an exercise left for the reader. Happy coding.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.