Iterate list by step in Emacs Lisp - emacs

I have a list in Elisp. How do i return a list consisting of every nth element starting from the 1st? In Python i have slice notation:
>>> range(10)[::3]
[0, 3, 6, 9]
I can't find anything helpful in dash.el list API, so i wrote my solution using loop macro:
(defun step (n xs)
(loop for x in xs by (lambda (xs) (nthcdr n xs))
collect x))
ELISP> (step 3 (number-sequence 0 10))
(0 3 6 9)
By the way, (lambda (xs) (nthcdr n xs)) could be rewritten with dash.el's partial application function -partial: (-partial 'nthcdr n).
loop macro seems like overkill. How do i return elements by step in Emacs Lisp?

dash package's slice supports step from version 2.7. Therefore Python's range(10)[1:7:2] is equivalent to:
(-slice (number-sequence 0 9) 1 7 2) ; (1 3 5)

Here's a short illustration, comparing using -partial and a plain lambda in a loop:
(require 'cl-lib)
(prog1 nil
(setq bigdata (number-sequence 1 10000)))
(defun every-nth-1 (n xs)
(cl-loop for x in xs by (lambda (xs) (nthcdr n xs))
collect x))
(defun every-nth-2 (n xs)
(cl-loop for x in xs by (-partial 'nthcdr n)
collect x))
(defmacro util-timeit (expr)
(let ((t-beg (float-time))
(res (dotimes (i 1000)
(eval expr)))
(t-end (float-time)))
(/
(- t-end t-beg)
1000)))
(setq time1
(util-timeit
(length (every-nth-1 3 bigdata))))
(setq time2
(util-timeit
(every-nth-2 3 bigdata)))
(message "%s" (/ time2 time1))
Calling eval-buffer gives me a result around 4. This means that
(lambda (xs) (nthcdr n xs)) is 4 times faster than (-partial 'nthcdr n),
at least without byte compilation.
With byte-compilation, it gives an astounding 12.2-13.6 times difference in performance
in favor of a plain lambda!

Related

LISP function which, given a number and a list, returns the first even number greater than n

I'm having trouble finding my error.
This keeps returning nil:
(even-greater-n 5 '(1 2 3 4 5 6 7))
(defun even-greater-n (n L)
(cond ((null L) nil)
((and (> (car L) n) (evenp n)) (car L))
(t (even-greater-n n (cdr L)))))
Your error
You are passing to evenp n
instead of (car L).
Iteration
This is relatively easy to implement using
loop:
(defun even-greater (n l)
(loop for k in l
when (and (< n k)
(evenp k))
return k))
(even-greater 5 '(1 2 3 4 5 6 7 8))
==> 6
Recursion
If you are required to use recursion, you can do it too:
(defun even-greater (n l)
(cond ((endp l) nil)
((and (< n (first l))
(evenp (first l)))
(first l))
(t (even-greater n (rest l)))))
(even-greater 3 '(1 2 3 4 5 6 7 8))
==> 4
Library
And, of course, Lisp has a very powerful library, including
find-if:
(defun even-greater (n l)
(find-if (lambda (k)
(and (< n k)
(evenp k)))
l))
(even-greater 2 '(1 2 3 4 5 6 7 8))
==> 4
You must look for (car L) is even or not.
Using find-if and a single, open-coded lambda function:
(defun even-greater (n list)
(find-if (lambda (item) (and (> item n) (evenp item))) list))
Using functional combinators:
;; Combine multiple functions with AND:
;; Returns a function of one-argument which
;; passes that argument to the functions in the list,
;; one by one. If any function returns nil, it stops
;; and returns nil. Otherwise it returns the value
;; returned by the last function:
(defun andf (&rest functions)
(lambda (arg)
(let (res)
(dolist (f functions res)
(unless (setf res (funcall f arg))
(return))))))
;; Returns a one-argument function which tests
;; whether its argument is greater than quant.
(defun greater (quant)
(lambda (arg) (> arg quant)))
;; "find it, if it is greater than n, and even"
(defun even-greater (n list)
(find-if (andf (greater n) #'evenp) list))

Mapcar in-place: destructively modify a list of lists

I have a list of lists: (setq xs (list (list 1 2 3) (list 4 5 6) (list 7 8 9))). I want to remove a first element from each list to get ((2 3) (5 6) (8 9)). It's easy to do it non-destructively: (mapcar 'cdr xs). But I want mutate the original list. I tried:
(mapcar (lambda (x) (setf x (cdr x))) xs)
(mapcar (lambda (x) (pop x)) xs)
But it doesn't work. How to change each list of xs variable in-place, without creating any temporary lists, as efficiently as possible?
Use MAP-INTO:
CL-USER 16 > (let ((s (list (list 1 2 3)
(list 4 5 6)
(list 7 8 9))))
(map-into s #'rest s))
((2 3) (5 6) (8 9))
#Rainer Joswig's answer is correct, use map-into. The link gives example implementation using loop macro. If you want to implement map-into from scratch, or you use Emacs Lisp, you can also do it using dotimes. In Emacs Lisp dotimes is implemented in subr.el and doesn't require CL package. This is map-into with 1 sequence to map into the result sequence:
(defun map-into (r f xs)
(dotimes (i (min (length r) (length xs)) r)
(setf (elt r i)
(funcall f (elt xs i)))))
For version with variable amount of sequences we must sprinkle our code with apply and mapcar:
(defun map-into (r f &rest xss)
(dotimes (i (apply 'min (length r) (mapcar 'length xss)) r)
(setf (elt r i)
(apply f (mapcar (lambda (s) (elt s i))
xss)))))
We see, however, that elt inside dotimes makes our algorithm work in O(n2). We can optimize it to work in O(n) by using mapl (thanks #Joshua Taylor).
(defun map-into (rs f xs)
(mapl (lambda (r x) (setf (car r) (funcall f (car x)))) rs xs))
(defun map-into (rs f &rest xss)
(mapl (lambda (r xs)
(setf (car r)
(apply f (car xs))))
rs
(apply 'mapcar 'list xss))) ;; transpose a list of lists
The reason setf doesn't work inside mapcar is that setf is a complex macro that expands into expression that can manipulate the data it mutates. In a lambda scope inside mapcar it has access only to a variable, local to this lambda, not to the sequence passed to mapcar itself, so how should it know, where to put a modified value back? That's why mapcar code in the question returns modified list of lists but doesn't mutate it in-place. Just try (macroexpand '(setf (elt xs 0) (funcall 'cdr (elt xs 0)))) and see for yourself.

Common Lisp Loop Trouble

I have some trouble fully understanding CL's Loop macro.
This is my code for Project Euler Nr. 32:
(defun number-to-list (nr)
(map 'list #'digit-char-p (prin1-to-string nr)))
(defun nine-digits-p (multiplicand multiplier )
(= (length (equationlist multiplicand multiplier
(* multiplicand multiplier))) 9))
(defun equationlist (multiplicand multiplier product)
(append (number-to-list multiplicand) (number-to-list multiplier)
(number-to-list product)))
(defun pandigital (multiplicand multiplier)
(equal (sort (equationlist multiplicand multiplier
(* multiplicand multiplier)) #'<)
'(1 2 3 4 5 6 7 8 9)))
(defun pandigital-list ()
(loop
for i from 1 to 2000 collect
(loop for j from 2 to 2000
when (and (nine-digits-p i j) (pandigital i j)) collect (* i j))))
(defun euler-32 ()
(reduce #'+ (reduce #'union (pandigital-list))))
Although this gives me the correct solution, my problem is with function "pandigital-list". Instead of collecting only the pandigital numbers, it returns a list filled with "NIL" and the few correct numbers.
How do I change this function to only return the numbers I am interested in ?
The problem is that the inner loop returns nil whenever it does not collect anything else. (Remember: in Common Lisp everything has a value.)
One solution is to redefine pandigital-list like this:
(defun pandigital-list ()
(loop for i from 1 to 2000
for sublist = (loop for j from 2 to 2000
when (and (nine-digits-p i j)
(pandigital i j))
collect (* i j))
when sublist collect sublist))

LISP: how to get running sum of a list? (without a global variable)

I am a LISP newbie.
To get the running sum of a list, I am writing like --
(setf sum 0.0)
(mapcar #'(lambda(x)
(setf sum (+ sum x)) sum) values))
For example, if you give '(1 2 3 4) as input, the above code returns '(1 3 6 10) as output and so forth.
Is it possible to do the same thing (in a more elegant way) without using the global variable sum ?
(loop for x in '(1 2 3 4) sum x into y collect y)
scanl is a oneliner:
(defun scanl (f init xs)
(loop for x in xs collect (setf init (funcall f init x))))
You could use loop, like this:
(defun running-sum (xs)
(loop with sum = 0
for x in xs
collect (setf sum (+ sum x))))
(running-sum '(1 2 3 4))
It's fundamentally the same thing, but it uses a local variable instead of a global one, and might be more clear.
Alternatively, you could define a recursive function, and a wrapper function:
(defun running-sum-recursive (xs)
(running-sum-recursive2 0 xs))
(defun running-sum-recursive2 (sum xs)
(if (eq xs nil)
nil
(let ((new-sum (+ sum (car xs))))
(cons new-sum (running-sum-recursive2 new-sum (cdr xs))))))
(running-sum-recursive '(1 2 3 4))
However this seems needlessly complicated to me when loop is available.
Note that in Haskell, you could do a running sum like this:
runningSum xs = scanl1 (+) xs
runningSum [1, 2, 3, 4]
The key here is the scanl1 function. It's possible that something similar exists in Lisp (and we've very nearly written it twice now), but I haven't used Lisp in a while.
Edit: After some searching, I don't think Common Lisp includes anything quite like scanl or scanl1, so here they are:
(defun scanl (f val xs)
(loop for x in xs
collect (setf val (funcall f val x))))
(defun scanl1 (f xs)
(cons (car xs)
(scanl f (car xs) (cdr xs))))
(scanl1 #'+ '(1 2 3 4))
Edit: Thanks to huaiyuan's answer for a suggestion about how the loops could be shortened.
Or you could use higher-order functions
(define (running-sum ls)
(cdr (reverse (foldl (lambda (y xs) (cons (+ (car xs) y) xs)) '(0) ls))))
Haskell does have a rich inventory of functions for list recursion, but we've got reduce at least. Here is an elementary (i. e. without the loop magic) functional solution:
(defun running-sum (lst)
(reverse (reduce (lambda (acc x)
(cons (+ (first acc) x) acc))
(rest lst)
:initial-value (list (first lst)))))
I'm using the head of the original list as the initial value and walk through the rest of the list adding sums at the head (because it's natural to add at the head), finally reversing the list thus obtained.
One can use reduce in most cases when there's a need to traverse a sequence accumulating a value.
Here is an elementary iterative solution using the push-nreverse idiom:
(defun running-sum (lst)
(let ((sums (list (first lst))))
(dolist (x (rest lst))
(push (+ x (first sums)) sums))
(nreverse sums)))
In Scheme I would calculate the sum of the list recursively using an accumulator. Like so:
; Computes a list of intermediary results of list summation
(define list-sum
(lambda (l)
(letrec ((recsum (lambda (lst acc acclst)
(if (pair? lst)
(recsum (cdr lst) (+ acc (car lst)) (cons acc acclst))
(cons acc acclst)))))
(recsum (cdr l) (car l) '()))))
Output:
> (list-sum '(1 2 3 4))
(10 6 3 1)
> (list-sum '(2 4 6 8 10))
(30 20 12 6 2)
>
The trick to recurse over a list is to take the first element/car off each time and pass the rest/cdr. You can keep intermediary results by using an extra parameter (called an accumulator) and pass the sum in that. I've used two accumulators above: one for the last sum and one for a list of all previous sums.
I've never done anything in LISP, so I can't tell if this translates directly to your dialect(?), but it's conceptually simple and I'm sure it's doable in LISP as well.
Do ask if something is not immediately clear. It's been a while since I've used this family of languages :)

Lisp style question: memoization (caution: contains the solution for project euler #14)

I am just trying to learn some Lisp, so I am going through project euler problems. I found problem no. 14 interesting (so if you are planning to solve this problems stop reading now, because I pasted my solution at the bottom). With my algorithm it was so slow, but after using memoization (I copied the function from Paul Graham's "on Lisp" book) it was much more faster (around 4 to 8 seconds).
My question is about this bunch of warnings that I got:
Am I doing something wrong? Can I improve my style?
> ;; Loading file
> /euler-lisp/euler-14.lisp
> ... WARNING in COLLATZ-SERIE :
> COLLATZ-SERIE-M is neither declared
> nor bound, it will be treated as if it
> were declared SPECIAL. WARNING in
> COLLATZ-SERIE : COLLATZ-SERIE-M is
> neither declared nor bound, it will be
> treated as if it were declared
> SPECIAL. WARNING in COMPILED-FORM-314
> : COLLATZ-SERIE-M is neither declared
> nor bound, it will be treated as if it
> were declared SPECIAL. (525 837799)
> Real time: 18.821894 sec. Run time:
> 18.029127 sec. Space: 219883968 Bytes GC: 35, GC time: 4.080254 sec. Las
> siguientes variables especiales no han
> sido definidas: COLLATZ-SERIE-M 0
> errores, 0 advertencias ;; Loaded file
This is the code:
(defun collatz (n)
(if (evenp n) (/ n 2) (+ (* 3 n) 1)))
(defun memoize (fn)
(let ((cache (make-hash-table :test #'equal)))
#'(lambda (&rest args)
(multiple-value-bind (val win) (gethash args cache)
(if win
val
(setf (gethash args cache)
(apply fn args)))))))
(defun collatz-serie (n)
(cond ((= n 1) (list 1))
((evenp n) (cons n (funcall collatz-serie-m (/ n 2))))
(t (cons n (funcall collatz-serie-m (+ (* 3 n) 1))))))
(defun collatz-serie-len (n)
(length (collatz-serie n)))
(setq collatz-serie-m (memoize #'collatz-serie))
(defun gen-series-pairs (n)
(loop for i from 1 to n collect
(list (collatz-serie-len i) i)))
(defun euler-14 (&key (n 1000000))
(car (sort (gen-series-pairs n) #'(lambda (x y) (> (car x) (car y))))))
(time (print (euler-14)))
Thanks a lot, and forgive the probable errors, I am just beginning with Lisp.
Br
UPDATE:
i want to share the final code that i wrote. using custom external hash table for memoization and improving the final loop.
(defvar *cache* (make-hash-table :test #'equal))
(defun collatz (n)
(if (evenp n) (/ n 2) (+ (* 3 n) 1)))
(defun collatz-serie (n)
(cond ((= n 1) (list 1))
((evenp n) (cons n (collatz-serie (/ n 2))))
(t (cons n (collatz-serie (+ (* 3 n) 1))))))
(defun collatz-serie-new (n)
(labels ((helper (n len)
(multiple-value-bind (val stored?) (gethash n *cache*)
(if stored?
val
(setf (gethash n *cache*) (cond ((= n 1) len)
((evenp n) (+ len (helper (/ n 2) len)))
(t (+ len (helper (+ (* 3 n) 1) len)))))))))
(helper n 1)))
;; learning how to loop
(defun euler-14 (&key (n 1000000))
(loop with max = 0 and pos = 0
for i from n downto 1
when (> (collatz-serie-new i) max)
do (setf max (collatz-serie-new i)) and do (setf pos i)
finally (return (list max pos))))
It is bad style to setq an unknown name. It is assumed that you mean to create a new global special variable, then set it, but this should be made explicit by introducing these bindings first. You do this at the top level by using defvar (or defparameter or defconstant) instead, and in lexical blocks by using let, do, multiple-value-bind or similar constructs.