99道lisp练习题----(一)列表操作

99道习题来自 http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html,并且该网页上有解答。

P01 (*) Find the last box of a list. (查找列表最后一个元素)Example:
* (my-last '(a b c d))
(D)
(defun my-last (lst)
  (if (null (cdr lst)) ;(cdr nil) equal nil
      lst
      (my-last (cdr lst))))
(defun my-last-1 (lst)
  (if (null lst)
      nil
      (let ((len (length lst)))
	(nthcdr (- len 1) lst))))
P02 (*) Find the last but one box of a list.(除最后一个元素外的列表)Example:
* (my-but-last '(a b c d))
(C D)
(defun my-but-last (lst)
  (let ((len (length lst)))
    (if (> len 1)
	(subseq lst (- (length lst) 2))
	nil)))
(defun my-but-last-1 (lst)
  (if (null (cddr lst))
      lst
      (my-but-last-1 (cdr lst))))
网页上有新的解法

P03 (*) Find the K'th element of a list. (查找列表的第K个元素)The first element in the list is number 1.
Example:
* (element-at '(a b c d e) 3)
C
(defun element-at (lst n)
  (cond ((null lst) nil)
	((= n 1) (car lst))
	(t (element-at (cdr lst) (- n 1)))))
P04 (*) Find the number of elements of a list.

(defun lenght-lst (lst)
  (if (null lst)
      0
      (1+ (lenght-lst (cdr lst)))))
P05 (*) Reverse a list.

(defun reverse-lst (lst)
  (if (null lst)
      nil
      (nconc (reverse-lst (cdr lst)) (list (car lst)))))
(defun reverse-lst-1 (lst)
  (labels ((rec (lst acc)
	     (if (null lst)
		 acc
		 (rec (cdr lst) (cons (car lst) acc)))))
    (rec lst nil)))

P06 (*) Find out whether a list is a palindrome. 

链表是否中心对称,将链表逆转,然后查看链表是否一样

A palindrome can be read forward or backward; e.g. (x a m a x).
(defun palindrome (lst)
  (let ((lst1 (reverse-lst-1 lst)))
    (labels ((rec (lst lst1)
	       (if (null lst)
		   t
		   (and (equal (car lst) (car lst1))
			(rec (cdr lst) (cdr lst1))))))
      (rec lst lst1))))
(defun palindrome-1 (lst)
  (let ((lst1 (reverse-lst-1 lst)))
    (equal lst lst1)))
P07 (**) Flatten a nested list structure.Transform a list, possibly holding lists as elements into a `flat' list by replacing each list with its elements (recursively).

Example:
* (my-flatten '(a (b (c d) e)))

(A B C D E)


(defun my-flatten (tree)
  (cond ((null tree) nil)
	((atom tree) (list tree))
	(t (nconc (my-flatten (car tree))
		  (my-flatten (cdr tree))))))

P08 (**) Eliminate consecutive duplicates of list elements.

If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.

Example:
* (compress '(a a a a b c c a a d e e e e))

(A B C A D E)

compress实现了删除重复相邻的元素,

本题还实现了一个通用的过程,首先将相邻相同的元素通过collect组织到一起,然后对相同的元素处理,通过combine将结果返回

(defun compress (lst)
  (if (null lst)
      lst
      (labels ((rec (lst acc prev)
		 (cond ((null lst) acc)
		       ((equal prev (car lst)) (rec (cdr lst) acc prev))
		       (t (rec (cdr lst) (cons (car lst) acc) (car lst))))))
	(nreverse (rec lst nil nil)))))
(defun collect (lst)
  (if (null lst)
      nil
      (labels ((rec (lst temp acc)
		 (cond ((null lst) (cons temp acc))
		       ((equal (car lst) (car temp))
			(rec (cdr lst) (cons (car lst) temp) acc))
		       (t (rec (cdr lst) (list (car lst)) (cons temp acc))))))
	(nreverse (rec (cdr lst) (list (car lst)) nil)))))

(defun general-process (combine fn lst)
  (labels ((rec (lst acc)
	     (if (null lst)
		 acc
		 (rec (cdr lst) (funcall combine (funcall fn (car lst))
					 acc)))))
    (nreverse (rec (collect lst) nil))))
							 
(defun compress-1 (lst)
  (general-process #'cons #'(lambda (sublst)
			      (car sublst)) lst))


P09 (**) Pack consecutive duplicates of list elements into sublists.If a list contains repeated elements they should be placed in separate sublists.

Example:
* (pack '(a a a a b c c a a d e e e e))

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

调用上面通用的处理过程

(defun pack (lst)
  (general-process #'cons #'identity lst))
P10 (*) Run-length encoding of a list.Use the result of problem P09 to implement the so-called run-length encoding data compression method. Consecutive duplicates of elements are encoded as lists (N E) where N is the number of duplicates of the element E.

Example:
* (encode '(a a a a b c c a a d e e e e))
((4 A) (1 B) (2 C) (2 A) (1 D)(4 E))
(defun encode (lst)
  (general-process #'cons #'(lambda (sub)
			      (list (lenght-lst sub) (car sub)))
		   lst))
P11 (*) Modified run-length encoding.Modify the result of problem P10 in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N E) lists.

Example:
* (encode-modified '(a a a a b c c a a d e e e e))
((4 A) B (2 C) (2 A) D (4 E))
(defun encode-modified (lst)
  (general-process #'cons 
		   #'(lambda (sub)
			      (if (= (lenght-lst sub) 1)
				  (car sub)
				  (list (lenght-lst sub) (car sub))))
		   lst))
P12 (**) Decode a run-length encoded list.Given a run-length code list generated as specified in problem P11. Construct its uncompressed version
(defun decode (lst)
  (reverse-lst-1 (general-process
		  #'nconc
		  #'(lambda (elem)
		      (let ((e (car elem)))
			(if (atom e)
			    (list e)
			    (loop for i from 1 to (car e)
			       collect (cadr e)))))
		  lst)))
P13 (**) Run-length encoding of a list (direct solution).Implement the so-called run-length encoding data compression method directly. I.e. don't explicitly create the sublists containing the duplicates, as in problem P09, but only count them. As in problem P11, simplify the result list by replacing the singleton lists (1 X) by X.

Example:
* (encode-direct '(a a a a b c c a a d e e e e))
((4 A) B (2 C) (2 A) D (4 E))
(defun encode-direct (lst)
  (labels ((rec (lst cur count acc)
	     (cond ((null lst)
		    (nreverse (cons (list count cur)
				    acc)))
		   ((equal cur (car lst))
		    (rec (cdr lst) cur (1+ count) acc))
		   (t (rec (cdr lst) (car lst) 1 
			   (cons (list count cur) acc))))))
    (mapcar #'(lambda (e)
		(if (= (car e) 1)
		    (cadr e)
		    e))
	    (if (null lst)
		nil
		(rec (cdr lst) (car lst) 1 nil)))))
P14 (*) Duplicate the elements of a list.Example:
* (dupli '(a b c c d))
(A A B B C C C C D D)
(defun general-rep (lst n)
  (mapcan #'(lambda (x)
	      (loop for i from 1 to n
		   collect x))
	  lst))
(defun dupli (lst)
  (general-rep lst 2))
P15 (**) Replicate the elements of a list a given number of times.Example:
* (repli '(a b c) 3)
(A A A B B B C C C)
(defun repli (lst n)
  (general-rep lst n))
P16 (**) Drop every N'th element from a list.Example:
* (drop '(a b c d e f g h i k) 3)
(A B D E G H K)
(defun drop (lst n)
  (labels ((rec (lst i)
		(cond ((null lst) nil)
		      ((= i n) (rec (cdr lst) 1))
		      (t (cons (car lst) (rec (cdr lst) (1+ i)))))))
	  (rec lst 1)))

这个题目还有其他方法,将每n个元素组织到一起,然后将每组最后一个元素删除,然后再重组到一起。

P17 (*) Split a list into two parts; the length of the first part is given.

Do not use any predefined predicates.

Example:
* (split '(a b c d e f g h i k) 3)
( (A B C) (D E F G H I K))
(defun copy-from (lst start end)
  (labels ((copy (lst len acc)
	     (if (= len 0)
		 (nreverse acc)
		 (copy (cdr lst) (1- len) (cons (car lst) acc)))))
    (copy (nthcdr start lst) (- end start) nil)))

(defun split (lst n)
  (list (copy-from lst 0 n) (copy-from lst n (lenght-lst lst))))
P18 (**) Extract a slice from a list.Given two indices, I and K, the slice is the list containing the elements between the I'th and K'th element of the original list (both limits included). Start counting the elements with 1.

Example:
* (slice '(a b c d e f g h i k) 3 7)

(C D E F G)

这个问题和subseq的目标相同

(defun slice (lst start end)
  (copy-from lst (- start 1) end))
P19 (**) Rotate a list N places to the left.Examples:
* (rotate '(a b c d e f g h) 3)
(D E F G H A B C)

* (rotate '(a b c d e f g h) -2)

(G H A B C D E F)

先将链表分割成两部分,然后调换位置即可

(defun rotate (lst n)
  (let ((len (lenght-lst lst)))
    (if (> n 0)
	(nconc (copy-from lst n len) (copy-from lst 0 n))
	(nconc (copy-from lst (+ len n) len) (copy-from lst 0 (+ len n))))))
P20 (*) Remove the K'th element from a list.Example:
* (remove-at '(a b c d) 2)
(A C D)
(defun remove-at (lst n)
  (if (= n 1)
      (cdr lst)
      (cons (car lst) (remove-at (cdr lst) (- n 1)))))
P21 (*) Insert an element at a given position into a list.Example:
* (insert-at 'alfa '(a b c d) 2)
(A ALFA B C D)
(defun insert-at (elem lst pos)
  (if (= pos 1)
      (cons elem lst)
      (cons (car lst) (insert-at elem (cdr lst) (1- pos)))))

P22 (*) Create a list containing all integers within a given range.

If first argument is smaller than second, produce a list in decreasing order.
Example:
* (range 4 9)
(4 5 6 7 8 9)
(defun range (a b)
  (loop for i from a to b collect i))

P23 (**) Extract a given number of randomly selected elements from a list.The selected items shall be returned in a list.
Example:
* (rnd-select '(a b c d e f g h) 3)
(E D A)

Hint: Use the built-in random number generator and the result of problem P20.

洗牌算法

(defun rnd-select (lst n)
  (if (= n 0)
      nil
      (let ((r (random (lenght-lst lst))))
	(cons (nth r lst)
	      (rnd-select (remove-at lst (1+ r)) (1- n))))))
P24 (*) Lotto: Draw N different random numbers from the set 1..M.The selected numbers shall be returned in a list.
Example:
* (lotto-select 6 49)
(23 1 17 33 21 37) Hint: Combine the solutions of problems P22 and P23.
(defun lotto-select (n m)
  (rnd-select (range 1 m) n))
P25 (*) Generate a random permutation of the elements of a list.Example:
* (rnd-permu '(a b c d e f))
(B A D C E F)

Hint: Use the solution of problem P23.
(defun rnd-permu (lst)
  (rnd-select lst (lenght-lst lst)))
P26 (**) Generate the combinations of K distinct objects chosen from the N elements of a listIn how many ways can a committee of 3 be chosen from a group of 12 people? We all know that there are C(12,3) = 220 possibilities (C(N,K) denotes the well-known binomial coefficients). For pure mathematicians, this result may be great. But  we want to really generate all the possibilities in a list.

Example:
* (combination 3 '(a b c d e f))

((A B C) (A B D) (A B E) ... )

算法如下,选择第0个元素,在剩下的链表中取n-1个元素,选择第1个元素,在后面的链表中取n-1个元素,n=1,分别取当前链表中的每一个元素。

(defun combine-1 (lst n)
  (cond ((or (< (lenght-lst lst) n)
	     (zerop n)) nil)
	((= n 1)
	 (mapcar #'(lambda (x)
		     (list x))
		 lst))
	(t (nconc (mapcar #'(lambda (elem)
			      (cons (car lst) elem))
			  (combine-1 (cdr lst) (1- n)))
		  (combine-1 (cdr lst) n)))))
(defun combination (n lst)
  (combine-1 lst n))
P27 (**) Group the elements of a set into disjoint subsets.a) In how many ways can a group of 9 people work in 3 disjoint subgroups of 2, 3 and 4 persons? Write a function that generates all the possibilities and returns them in a list.

Example:
* (group3 '(aldo beat carla david evi flip gary hugo ida))
( ( (ALDO BEAT) (CARLA DAVID EVI) (FLIP GARY HUGO IDA) )
... )

b) Generalize the above predicate in a way that we can specify a list of group sizes and the predicate will return a list of groups.

Example:
* (group '(aldo beat carla david evi flip gary hugo ida) '(2 2 5))
( ( (ALDO BEAT) (CARLA DAVID) (EVI FLIP GARY HUGO IDA) )
... )

Note that we do not want permutations of the group members; i.e. ((ALDO BEAT) ...) is the same solution as ((BEAT ALDO) ...). However, we make a difference between ((ALDO BEAT) (CARLA DAVID) ...) and ((CARLA DAVID) (ALDO BEAT) ...).

You may find more about this combinatorial problem in a good book on discrete mathematics under the term "multinomial coefficients".

(defun flatten-2 (lst)
  (remove-duplicates (reduce #'append lst)))
(defun get-n-elements-from (lst used n)
  (let* ((f1 (flatten-2 used))
	 (left (set-difference lst f1)))
    (labels ((rec (lst n)
	       (cond ((or (null lst)
			  (< (lenght-lst lst) n))
		      nil)
		     ((= n 1) (mapcar #'(lambda (x)
					  (list x))
				      lst))
		     (t (append
			 (rec (cdr lst) n)
			 (mapcar #'(lambda (x)
				     (cons (car lst) x))
				 (rec (cdr lst) (1- n))))))))
      (rec left n))))
(defun group-list (lst ln)
  (let ((init (mapcar #'(lambda (e) (list e))
		      (get-n-elements-from lst nil (car ln)))))
    (labels ((rec (ln acc)	       
	       (let ((len (lenght-lst ln)))
		 (cond ((= len 1)
			(mapcar #'(lambda (e)
				    (nconc 
				     (get-n-elements-from lst 
							  e (car ln))
				     e))
				acc))
		       (t (rec (cdr ln)
			       (mapcan #'(lambda (e)
					   (let ((tlst 
						  (get-n-elements-from 
						   lst
						   e
						   (car ln))))
					     (mapcar #'(lambda (new)
							 (cons new e))
						     tlst)))
				       acc)))))))
      (rec (cdr ln) init))))

(defun group (lst lstn)
  (mapcar #'(lambda (e)
	      (reverse e))
	  (group-list lst lstn)))

 (defun group3 (lst)
   (group lst '(2 3 4)))
P28 (**) Sorting a list of lists according to length of sublistsa) We suppose that a list contains elements that are lists themselves. The objective is to sort the elements of this list according to their  length. E.g. short lists first, longer lists later, or vice versa.

Example:
* (lsort '((a b c) (d e) (f g h) (d e) (i j k l) (m n) (o)))
((O) (D E) (D E) (M N) (A B C) (F G H) (I J K L))

b) Again, we suppose that a list contains elements that are lists themselves. But this time the objective is to sort the elements of this list according to their  length frequency; i.e., in the default, where sorting is done ascendingly, lists with rare lengths are placed first, others with a more frequent length come later.

Example:
* (lfsort '((a b c) (d e) (f g h) (d e) (i j k l) (m n) (o)))
((i j k l) (o) (a b c) (f g h) (d e) (d e) (m n))

Note that in the above example, the first two lists in the result have length 4 and 1, both lengths appear just once. The third and forth list have length 3 which appears twice (there are two list of this length). And finally, the last three lists have length 2. This is the most frequent length.

这个题目要利用第一问,首先按照元素的长度排序,然后统计每一长度元素的个数,并且记录下来,排序的时候查询当前元素长度出现的次数作为key

(defun lsort (lst)
  (sort lst #'(lambda (ele ele2)
		(< (length ele) (length ele2)))))

(defun lfsort (lst)
  (let* ((lens (mapcar #'(lambda (ele)
			  (length ele))
		       lst))
	 (s-l (sort lens #'<))
	 (len-c (general-process #'cons 
				 #'(lambda (subl)
				     (list (car subl) (length subl)))
				 s-l)))
    (sort lst #'(lambda (lst1 lst2)
		  (let ((len1 (length lst1))
			(len2 (length lst2)))
		    (< (cadr (assoc len1 len-c))
		       (cadr (assoc len2 len-c))))))))


你可能感兴趣的:(函数式编程)