Is there a Common Lisp function that will swap two elements in a list given their indices and return the modified list?
You can use rotatef:
(rotatef (nth i lst) (nth j lst))
Of course, list indexing can be expensive (costing O(size of list)), so if you do this with any regularity, you'd rather want to use an array:
(rotatef (aref arr i) (aref arr j))
I would avoid indexing into the list twice by using nthcdr to get the cdr of the cons cell containing the first element that you want to swap and then use elt to get the remaining element out of the sublist. This means that you only have to actually index starting from the head of the list once.
(let ((list-tail (nthcdr i list)))
(rotatef (car list-tail)
(elt list-tail (- j i)))
list)
At least from my perspective, this is sufficiently tedious to justify a function.
Related
Let's say my reverse function in Scheme is coded in the following way:
(define (reversee lst)
(if (null? lst)
'()
(append (reversee (cdr lst)) (list (car lst)))))
Why is the performance of this procedure O(n^2)?
Well, consider what the function has to do:
for a zero-element list it just returns the list.
for a 1 element list it appends the reverse of a zero element list and the first element.
for a 2 element list it appends the reverse of a 1 element list and the first element
... and so on.
It's obvious from this that to reverse an n-element list it calls itself recursively n times. So this looks like the time complexity is O(n), right?
Not so fast: for each recursive call it appends two lists. So we need to worry about the complexity of append. Well, let's write the best append we can:
(define (my-append l1 l2)
(if (null? l1)
l2
(cons (car l1) (my-append (cdr l1) l2))))
OK, so what's the complexity of this? First of all, only depends on the length of l1, so we only need to worry about that:
if l1 is a zero-element list it returns l2
if l2 is a 1-element list is conses its first element onto the result of appending the rest of it to l2
... and so on
So to append an n-element list to some other list there are n steps. So what is the time complexity of each of these steps? Well, it's constant: cons and cdr and car take constant time. So the time complexity of append is the length of the first list.
So this means that the time complexity of your reverse function is
n + n-1 + n-2 + ... + 1
It's a famous result that the value of such a sum is n(n+1)/2 (you do get this result by writing it as ((n + 1) + (n - 1 + 2) + ... (1 + n))/2 = ((n + 1) + ... (n + 1))/2 with n terms in the sum. So the complexity is n(n+1), which is asymptotically equal to n^2.
There is a better version of reverse, of course.
A more readable and understandable O(N) reverse....
(define (reverse lst)
(let reverser ((lst lst)
(reversed '()))
(if (null? lst)
reversed
(reverser (cdr lst) (cons (car lst) reversed)))))
(reverse '(1 2 3))
By building up the reversed list as it goes with a tail-recursive approach, it only has to traverse the list once.
I am trying to write a function that takes a list of divisors, a list of numbers to test and applies drop-divisible for each element of the list of divisors. I am supposed to use filter, map or foldl and no recursion
I wrote the drop-divisible function:
(define (drop-divisible l n)
(cond
[(empty? l) empty]
[(empty? (rest l)) l]
(let ([i (first l)])
(if (zero? (modulo i n))
(drop-divisible (rest l) n)
(cons i (drop-divisible(rest l)n))))]))
That seems to work, but I'm confused on how I can call drop-divisible for each element in the list when it only wants one list and an integer as a parameter?
Hopefully, that makes sense, thanks
When you want "all the elements of this list except the ones that meet such-and-such criterion", the filter function provides an easy way to do that:
(define (drop-divisible l n)
(filter (λ (i) (not (zero? (modulo i n))))
l))
> (drop-divisible '(4 6 9 8 12 14) 3)
'(4 8 14)
filter constructs a new list, containing only the items of the original list that meet your criterion. The first argument to filter is a function that takes a single element of the list and returns #f if the element should be skipped when creating the new list, and returns any other value to include the element in the new list. The second argument to filter is the list to filter.
In other words, filter does exactly what your code does, but it's generalized to apply any filtering criterion.
I am trying to figure out how to access the elements in a nested list in LISP. For example:
((3 (1 7) (((5)))) 4)
If I use dolist, i run into the brackets. Is there any method to just get the elements from the list?
This is actually a surprisingly subtle question! It's in some ways the equivalent of asking: how do I get the nested elements of an HTML DOM, by specifying a pattern. (more on that aspect later)
If you just want to get the non-list elements as a sequence, e.g.
((3 (1 7) (((5)))) 4) -->
(nth 3 (3 1 7 5 4)) -->
5
You can use the 'cheat' way: the flatten function in the CL alexandria library. (via quicklisp)
(ql:quicklisp :alexandria)
(nth 3 (alexandria:flatten '((3 (1 7) (((5)))) 4)))
Which gives us the sought after,
5
But, the alexandrian function is simple enough that we can take a look at the source code itself:
(defun flatten (list)
(cond
((null list)
nil)
((consp (car list))
(nconc (flatten (car list)) (flatten (cdr list))))
((null (cdr list))
(cons (car list) nil))
(t
(cons (car list) (flatten (cdr list))))))
As you can see, it's a recursive function -- at each level of recursion it asks the question: what is the object that I'm flattening? If it's the empty list, return nil. I'm done!
Otherwise it has to be a non empty list. If the first element of the list is also a list then flatten that and also flatten the cdr of the function argument list and concatenate the results.
If the first element is not a list and the second element is '(), that must mean we have a list with one element: return it.
The final case case, which exhausts our possibilities is that the first element in the list is an atom while the rest of the list is a list with at least one element. In that case concatenate the first element with the results of a flatten performed on the rest of the list.
The fact that the description in English is so ponderous shows the power of recursion, (and also my own lack of fluency when describing it).
But there's actually another way your question could interpreted: if I have a list that looks something like: ((n1 (n2 n3) (((n4)))) n5) How do I get at n2, even if n2 is itself a list? Our previous recursive algorithm won't work -- it depends on n2 not being a list to know when to stop. But, we can still use recursion and the very list we're searching as the basis for a pattern:
;; For each element in our pattern list look for a corresponding
;; element in the target, recursing on lists and skipping atoms that
;; don't match.
(defun extract-from-list (pattern target to-find)
(dotimes (i (length pattern))
(let ((ith-pattern (nth i pattern)))
(cond
((consp ith-pattern)
(let ((results
(extract-from-list (nth i pattern)
(nth i target)
to-find)))
(when results
(return results))))
(t
(if (eq to-find ith-pattern)
(return (nth i target))))))))
Note that,
(extract-from-list
'((n1 (n2 n3) (((n4)))) n5) ;; The pattern describing the list.
'((3 (1 7) (((5)))) 4) ;; The list itself.
'n4) ;; which of the elements we want.
still returns the old answer:
5
But,
(extract-from-list
'((n1 (n2 n3) (n4)) n5) ;; The pattern describing the list, note (n4) rather than (((n4)))
'((3 (1 7) (((5)))) 4) ;; The list itself.
'n4) ;; The element we want to pull from the list
Returns
((5))
Magic! One of the aspects of Lisp that makes it so extraordinarily powerful.
I'm really puzzled on how to do this... I can't even figure out how to start, I know how to do it for a binary tree but I want to be able to do it with any form of nested list, can anyone help me out please?
For this one, you need to use the template for traversing an arbitrarily nested list of elements. For example, study this procedure that copies an arbitrarily nested list:
(define (copy lst)
(cond ((null? lst) ; if list is empty
'()) ; return the empty list
((not (list? (car lst))) ; if current element is not a list
(cons (car lst) ; cons current element
(copy (cdr lst)))) ; with the rest of the list
(else ; if current element is a list
(cons (copy (car lst)) ; cons recursive call over current element
(copy (cdr lst)))))) ; with recursive call over rest of the list
A little convention first. Let's say that 1 is the base level, and that all the elements returned will be in a flat output list (without preserving the original structure of the input list). For example:
(elements-level '(1 2 3) 1)
; => '(1 2 3)
(elements-level '(1 (2) 3) 2)
; => '(2)
With the above template in mind, let's see how we can modify it for solving the problem at hand. I'll let you fill-in the blanks, because the question looks like homework:
(define (elements-level lst lvl)
(cond ((or (null? lst) (< lvl 1)) ; if list is empty or below level
'()) ; return the empty list
((not (list? (car lst))) ; if current element is not a list
(if (= lvl <???>) ; if `lvl` is the base level
(cons <???> ; cons current element in list
(elements-level <???> lvl)) ; and advance recursion over cdr part
(elements-level <???> lvl))) ; else advance recursion over cdr part
(else ; if current element is a list
(append ; use `append` for flattening the list
(elements-level <???> <???>) ; recur over car, decrease one level
(elements-level <???> <???>))))) ; recur over cdr, keep the same level
Test the procedure with this list, it must return '(1) for level 1, '(2) for level 2, and so on:
(elements-level '(1 (2 (3 (4 (5))))) 1)
; => '(1)
I think you can use recursion with steps as below:
Define a list to hold all elements at nth depth.
create a recursion function, which takes nested list, new list and n as argument
For each element of the nested loop, call the recursion function itself by passing the child list and depth as n-1.
Add all elements of the nested list to new list when n = 0.
Once this method is done, you will all elements of depth n in the new list.
Possible Enhancement:
If it is possible the some of the list elements don't extend up to nth level, then you may want to check the type of elements before calling the recursion method. If it's of type leaf, then simply add the element in the new list.
i am trying to do the following in Scheme:
List<int> list = new List<int>();
List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
list1.Add(2);
list1.Add(4);
list1.Add(6);
list1.Add(8);
for (int i = 0; i < list.Count; i++)
{
for (int p = 0; p < list1.Count; p++)
{
list2.Add(list[i] * list1[p]);
}
}
as seen in the code above, I am trying to multiply each element of the first list with every element in the second list. So 1*2, 1*4, 1*6, 1*8, then going to the next element, 2*2,2*4.. etc.
I am having trouble implementing this into Scheme. I tried using the map function but this doesn't seem to work the way I want it to. Any ideas?
We start by defining the two input lists, I renamed them since list is a built-in procedure in Scheme and is not a good idea to overwrite it):
(define l '(1 2 3 4))
(define l1 '(2 4 6 8))
I'm assuming that you want your result list to be "flat" - e.g., it doesn't contain lists of elements, only elements (if you're ok with having a list of lists in l2, simply delete the call to flatten below). For that, we need to define the flatten procedure:
(define (atom? x)
(and (not (pair? x)) (not (null? x))))
(define (flatten lst)
(cond ((null? lst) empty)
((atom? lst) (list lst))
(else (append (flatten (car lst))
(flatten (cdr lst))))))
Finally, the problem at hand. It's simple once you understand how to nest two map procedures - take a look at the nested mappings section in the book SICP.
(define l2
(flatten
(map (lambda (i)
(map (lambda (j)
(* i j))
l1))
l)))
At this point, l2 contains the expected answer:
(2 4 6 8 4 8 12 16 6 12 18 24 8 16 24 32)
Óscar has given a very complete answer to this question, but I wanted to add two minor notes:
The Scheme dialect Racket has a nice built-in form called for*/list which does exactly this sort of thing:
(for*/list ([i '(1 2 3 4)]
[j '(2 4 6 8)])
(* i j))
Also, instead of using your own or the library's flatten function in the nested-maps solution, you could replace the outer map with append-map from SRFI-1. There are plenty of other ways too, of course ;-)
I can't believe nobody has given the most straightforward answer: nested uses of map:
(append-map (lambda (x)
(map (lambda (y) (* x y))
(list 2 4 8 6)))
(list 1 2 3 4))
append-map is a simple variant of map that assumes that the mapping function returns a list, so it concatenates all the result lists. This is a library function in most serious Scheme systems (it's in the SRFI-1 library), but here's a simple, incomplete definition (a complete definition would handle multiple argument lists):
(define (append-map f xs)
(concat (map f xs)))
;;;
;;; Turns a list of lists into a list by appending all the top-level sublists.
;;; This is also a common library function.
;;;
(define (concat lists)
(if (null? lists)
'()
(append (car lists)
(concat (cdr lists)))))