3

I'm working on a program that takes a list of elements and each individual element is duplicated based on an integer contained in a 2nd list of integers. for example if I had a list of

(A B C D)

being duplicated by:

(1 5 4 2)

I would have

(A B B B B B C C C C D D)

So far I have

(defun COPY (X Y) 
  (if (zerop Y) 
      nil 
      (cons S (COPY X (1 - Y)))))

Of course this is only duplicating a single element a single number of times. Does anybody have a good idea how to go about this?

Barmar
  • 741,623
  • 53
  • 500
  • 612
joshbusiness
  • 128
  • 7

2 Answers2

7

Use mapcan and make-list (which is the library version of your copy):

(mapcan (lambda (letter num)
          (make-list num :initial-element letter))
        '(A B C D) '(1 5 4 2))
==> (A B B B B B C C C C D D)

or just

(mapcan #'copy '(A B C D) '(1 5 4 2))

If you are required to use simple recursion, you can also write

(defun copy-list-elements (elements counts)
  (and elements counts
       (let ((count (pop counts)))
         (if (plusp count)
             (cons (car elements)
                   (copy-list-elements elements
                                       (cons (1- count) counts)))
             (copy-list-elements (cdr elements)
                                 counts)))))
(copy-list-elements '(A B C D E) '(1 5 4 0 2))
==> (A B B B B B C C C C E E)

Note that the recursive version is longer and probably slower.

sds
  • 58,617
  • 29
  • 161
  • 278
3

Loop over the two lists, call copy, and append the results.

(loop for letter in letters
      for count in counts
      nconcing (copy letter count))
Barmar
  • 741,623
  • 53
  • 500
  • 612