Search code examples
lispcommon-lisp

How to simulate collecting in nested loop for


I want to create a list of pairs (a . b) with 1 < a < b <= n up to n, e.g. n = 5:

((2 . 3) (2 . 4) (3 . 4) (2 . 5) (3 . 5) (4 . 5))

(The order of the pairs is not critical.)

I came up with the code

(defun create-pairs (upper-bound)
  (loop for i from 3 to upper-bound
        for j from 2 to (1- upper-bound)
          collecting (cons j i)))

but that doesn't do what I wanted

* (create-pairs 5)
((2 . 3) (3 . 4) (4 . 5))

since the loops are incrementing at the same time.

Therefore I tried this

(defun create-pairs (upper-bound)
  (loop for i from 3 to upper-bound do
    (loop for j from 2 to (1- upper-bound)
      collecting (cons j i))))

with the result:

* (create-pairs 5)

NIL

I don't remember where but I read that it's not possible to use collecting in constructs like my second try.

So how do I get the result I want to have? Isn't it possible to solve this with loop for?


Solution

  • You are almost there - you just need to accumulate the results of the inner loop:

    (defun create-pairs (upper-bound)
      (loop for i from 3 to upper-bound nconc
        (loop for j from 2 below i
          collect (cons j i))))
    (create-pairs 5)
    ==> ((2 . 3) (2 . 4) (3 . 4) (2 . 5) (3 . 5) (4 . 5))